본문 바로가기
JavaScript

[JavaScript] 비동기 처리 완벽 정리: Callback → Promise → Async/Await

by 요료료룡 2026. 4. 6.

자바스크립트는 싱글 스레드 언어입니다. 그런데도 수많은 네트워크 요청과 파일 I/O를 막힘없이 처리할 수 있는 이유는 바로 비동기 처리 메커니즘 덕분입니다. 이번 포스팅에서는 콜백(Callback)부터 시작해 Promise, 그리고 현대적인 Async/Await까지 비동기 처리의 발전 과정을 코드와 함께 살펴보겠습니다.

1단계: Callback - 가장 기본적인 비동기 처리

콜백은 함수를 다른 함수의 인자로 전달해 나중에 실행하는 패턴입니다. 이해하기는 쉽지만, 중첩이 깊어지면 '콜백 지옥(Callback Hell)'이 발생합니다.

// 콜백 지옥 예시
getUser(userId, function(user) {
  getOrders(user.id, function(orders) {
    getOrderDetail(orders[0].id, function(detail) {
      // 점점 깊어지는 들여쓰기...
      console.log(detail);
    });
  });
});
2단계: Promise - 콜백 지옥 탈출

Promise는 비동기 작업의 완료 또는 실패를 나타내는 객체입니다. .then()과 .catch()를 체이닝해 가독성을 크게 높일 수 있습니다.

// Promise 체이닝
getUser(userId)
  .then(user => getOrders(user.id))
  .then(orders => getOrderDetail(orders[0].id))
  .then(detail => console.log(detail))
  .catch(err => console.error('오류 발생:', err));
3단계: Async/Await - 동기 코드처럼 쓰는 비동기

Async/Await는 Promise를 기반으로 하되, 마치 동기 코드처럼 읽히는 문법을 제공합니다. ES2017(ES8)에 도입되었으며 현재 가장 널리 사용되는 비동기 패턴입니다.

// Async/Await - 가장 깔끔한 방식
async function fetchOrderDetail(userId) {
  try {
    const user = await getUser(userId);
    const orders = await getOrders(user.id);
    const detail = await getOrderDetail(orders[0].id);
    console.log(detail);
  } catch (err) {
    console.error('오류 발생:', err);
  }
}

세 가지 방식을 이해하면 레거시 코드 리팩토링부터 최신 코드 작성까지 유연하게 대응할 수 있습니다.

Tip💡 여러 비동기 작업을 병렬로 처리할 때는 Promise.all()을 활용하세요. await를 반복문 안에서 사용하면 순차 실행이 되므로 성능에 주의하세요.

'JavaScript' 카테고리의 다른 글

[JavaScript] 탐색 메서드  (0) 2024.04.05
[JavaScript] 명시적 형변환  (0) 2024.04.04