기술 가이드

자바스크립트 비동기 처리: 콜백, 프로미스, 그리고 async/await

taeridad19 2025. 4. 12. 10:45

비동기 처리란 무엇인가?

**비동기 처리(Asynchronous Processing)**란, 코드가 실행되는 동안 다른 작업을 기다리지 않고 동시에 처리할 수 있도록 하는 방식입니다.
자바스크립트(JavaScript)는 기본적으로 싱글 스레드(Single Thread) 환경이기 때문에, 비동기 로직이 필수적입니다.

예를 들어, 사용자의 버튼 클릭, 서버에서 데이터 받아오기(AJAX), 파일 읽기, 타이머 설정 등은 시간이 오래 걸릴 수 있으므로 비동기 방식으로 처리해야 UI가 멈추지 않고 부드럽게 동작합니다.


콜백 함수 (Callback Function)

콜백 함수란?

콜백 함수는 어떤 함수에 인수로 전달되어 특정 시점에 호출되는 함수입니다. 비동기 작업이 완료되었을 때 실행되도록 예약할 수 있습니다.

예제:

function fetchData(callback) {
  setTimeout(() => {
    console.log("데이터를 가져왔습니다!");
    callback();
  }, 1000);
}

fetchData(() => {
  console.log("콜백 실행 완료!");
});

단점: 콜백 지옥

콜백을 중첩해서 사용하다 보면 다음과 같이 **“콜백 지옥(Callback Hell)”**에 빠지기 쉽습니다.

login(user, () => {
  getProfile(user, () => {
    getPosts(user, () => {
      showFeed();
    });
  });
});

코드가 가독성이 떨어지고 유지보수가 어려워지는 문제가 발생합니다.


프로미스(Promise)

프로미스란?

**프로미스(Promise)**는 비동기 작업의 성공(resolve) 또는 실패(reject)를 처리하는 객체입니다. 콜백보다 구조화된 에러 처리연결된 체이닝이 가능해 보다 직관적인 코드 작성이 가능합니다.

기본 구조:

const promise = new Promise((resolve, reject) => {
  // 비동기 작업
  if (성공) {
    resolve(결과값);
  } else {
    reject(에러);
  }
});

예제:

function fetchData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("데이터를 성공적으로 불러왔습니다!");
    }, 1000);
  });
}

fetchData()
  .then(data => {
    console.log(data);
  })
  .catch(err => {
    console.error(err);
  });

장점:

  • 가독성 향상
  • 체이닝 가능 (.then().then())
  • 에러를 .catch()로 관리 가능

async/await

async/await란?

async/await는 프로미스를 기반으로 만들어진 비동기 처리 문법의 최신 방식입니다.
async 키워드가 붙은 함수 내부에서 await를 사용하면, 해당 작업이 완료될 때까지 기다렸다가 다음 줄을 실행합니다.

사용 예:

async function loadData() {
  try {
    const data = await fetchData();  // Promise가 반환되어야 함
    console.log(data);
  } catch (err) {
    console.error("에러 발생:", err);
  }
}

특징:

  • 마치 동기식 코드처럼 읽기 쉽고 직관적
  • try/catch로 에러를 처리할 수 있음
  • await는 반드시 async 함수 안에서만 사용 가능

세 가지 방식 비교

항목  콜백 함수  프로미스(Promise) async/await
가독성 낮음 (콜백 지옥 발생) 중간 (체이닝 가능) 높음 (동기식처럼 작성)
에러 처리 try-catch 어려움 .catch() 사용 가능 try-catch 사용 가능
디버깅 편의성 어려움 중간 좋음
코드 길이 길어짐 줄어듦 가장 짧음

실전 예제: API 호출 시 async/await 활용하기

async function getUserInfo() {
  try {
    const response = await fetch('https://jsonplaceholder.typicode.com/users/1');
    const data = await response.json();
    console.log("유저 정보:", data);
  } catch (error) {
    console.error("에러 발생:", error);
  }
}

getUserInfo();

이렇게 작성하면 비동기 요청이 마치 동기 방식처럼 순차적이고 가독성 있게 처리됩니다.


결론: 어떤 방식이 가장 좋을까?

  • 콜백 함수는 단순한 작업에는 빠르지만 복잡해지면 지옥을 경험할 수 있음
  • 프로미스는 체이닝을 통한 작업 순서 제어가 가능함
  • async/await는 가장 최신 방식으로, 가독성과 유지보수성이 가장 뛰어남

현재는 대부분의 프로젝트에서 async/await을 표준으로 채택하고 있습니다. 하지만 모든 방식의 구조를 이해하고 있어야 다양한 상황에 유연하게 대응할 수 있습니다.