블로그로 돌아가기
기술

JavaScript 비동기 프로그래밍 쉽게 이해하기

콜백, Promise, async/await까지. JavaScript의 비동기 처리 방식을 단계적으로 쉽게 설명합니다.

2026년 3월 4일2분 읽기

비동기란 무엇인가?

JavaScript는 기본적으로 단일 스레드(Single Thread) 언어입니다. 한 번에 하나의 작업만 처리할 수 있다는 뜻이죠.

그런데 웹 애플리케이션에서는 서버에서 데이터를 받아오거나, 타이머를 설정하거나, 파일을 읽는 등 시간이 걸리는 작업이 많습니다. 이런 작업들을 기다리면서 다른 작업도 할 수 있게 해주는 것이 바로 비동기 프로그래밍입니다.

1단계: 콜백(Callback)

비동기의 가장 기본적인 방식은 콜백 함수입니다.

setTimeout(function() {
  console.log("1초 후에 실행됩니다!");
}, 1000);
 
console.log("이건 먼저 실행됩니다.");
// 출력: "이건 먼저 실행됩니다."
// 1초 후 출력: "1초 후에 실행됩니다!"

콜백 지옥

하지만 콜백이 중첩되면 코드가 복잡해집니다:

fetchUser(userId, function(user) {
  fetchPosts(user.id, function(posts) {
    fetchComments(posts[0].id, function(comments) {
      // 코드가 오른쪽으로 계속 밀려납니다...
      console.log(comments);
    });
  });
});

이를 "콜백 지옥(Callback Hell)" 이라고 합니다.

2단계: Promise

Promise는 콜백 지옥을 해결하기 위해 도입되었습니다.

fetch('/api/user/1')
  .then(response => response.json())
  .then(user => fetch(`/api/posts/${user.id}`))
  .then(response => response.json())
  .then(posts => console.log(posts))
  .catch(error => console.error('에러:', error));

Promise는 세 가지 상태를 가집니다:

  • Pending(대기): 아직 결과가 없는 상태
  • Fulfilled(성공): 작업이 성공적으로 완료된 상태
  • Rejected(실패): 작업이 실패한 상태

3단계: async/await

ES2017에 도입된 async/await는 비동기 코드를 동기 코드처럼 읽기 좋게 만들어줍니다.

async function loadUserPosts(userId) {
  try {
    const userResponse = await fetch(`/api/user/${userId}`);
    const user = await userResponse.json();
 
    const postsResponse = await fetch(`/api/posts/${user.id}`);
    const posts = await postsResponse.json();
 
    return posts;
  } catch (error) {
    console.error('데이터를 불러오는데 실패했습니다:', error);
  }
}

훨씬 읽기 쉽죠?

주의사항

await는 반드시 async 함수 안에서만 사용할 수 있습니다. 함수 앞에 async 키워드를 잊지 마세요!

병렬 처리: Promise.all()

여러 비동기 작업을 동시에 실행하고 싶을 때는 Promise.all()을 사용합니다.

async function loadDashboard() {
  // 순차 실행 (느림)
  // const user = await fetchUser();
  // const posts = await fetchPosts();
  // const stats = await fetchStats();
 
  // 병렬 실행 (빠름)
  const [user, posts, stats] = await Promise.all([
    fetchUser(),
    fetchPosts(),
    fetchStats()
  ]);
 
  return { user, posts, stats };
}

정리

방식장점단점
콜백단순하고 직관적중첩 시 복잡해짐
Promise체이닝으로 가독성 향상여전히 then/catch 반복
async/await동기 코드처럼 읽기 쉬움브라우저 지원 확인 필요

마치며

비동기 프로그래밍은 처음에는 어렵게 느껴지지만, 콜백 → Promise → async/await 의 발전 과정을 이해하면 자연스럽게 감이 잡힙니다. 특히 현대 JavaScript 개발에서 async/await는 필수 개념이니 꼭 익혀두세요!

새 글을 이메일로 받아보세요 ✉️

새 글이 올라오면 바로 알려드릴게요