[JavaScript] 콜백 지옥을 피하는 방법 - Promise와 async/await

Byeonghyeon·2025년 1월 26일

공부

목록 보기
14/21

Promiseasync/await은 JavaScript에서 비동기 작업을 처리하는 방식이다.

Promise

Promise는 비동기 작업이 완료되었을 때, 그 결과를 처리할 수 있는 객체이다.

비동기 작업이 성공적으로 완료되면 resolve()가 호출되고, 실패하면 reject()가 호출된다.

Promise의 상태

  • pending : 비동기 작업이 아직 완료되지 않은 상태
  • fulfilled : 비동기 작업이 성공적으로 완료된 상태
  • rejected : 비동기 작업이 실패한 상태

프로미스의 메소드

  1. .then(onFulfilled, onRejected) : 프로미스가 fulfilled 상태가 되었을 때 실행되는 콜백 함수와 rejected 상태일 때 실행되는 콜백 함수를 정의한다.
  2. .catch(onRejected) : 프로미스가 rejected 상태가 되었을 때 실해오디는 콜백 함수이며 주로 오류 처리를 위해 사용된다.
  3. .finally(onFinally) : 프로미스의 상태와 상관없이 항상 실행되는 함수이다.

예시

let promise = new Promise((resolve, reject) => {
  let success = true;

  if (success) {
    resolve("작업 성공");
  } else {
    reject("작업 실패");
  }
});

promise
  .then(result => {
    console.log(result); // "작업 성공"
  })
  .catch(error => {
    console.log(error); // "작업 실패" (실패한 경우)
  })
  .finally(() => {
    console.log("비동기 작업이 끝났습니다.");
  });
  • 비동기 처리 성공 : resolve 함수를 호출해 프로미스를 fulfilled 상태로 변경
  • 비동기 처리 실패 : reject 함수를 호출해 프로미스를 rejected 상태로 변경

프로미스의 상태는 resilve 또는 reject 함수를 호출하는 것으로 결정된다.

Promise의 체이닝

프로미스는 .then().catch()를 체이닝하여 여러 개의 비동기 작업을 순차적으로 처리할 수 있게 해준다. 하나의 프로미스가 완료된 후 다음 프로미스를 실행하는 방식이다.

let promise1 = new Promise((resolve, reject) => {
  resolve("첫 번째 작업 완료");
});

promise1
  .then(result => {
    console.log(result); // "첫 번째 작업 완료"
    return new Promise((resolve, reject) => {
      resolve("두 번째 작업 완료");
    });
  })
  .then(result => {
    console.log(result); // "두 번째 작업 완료"
    return "세 번째 작업 완료";
  })
  .then(result => {
    console.log(result); // "세 번째 작업 완료"
  })
  .catch(error => {
    console.log(error);
  });

async/await

async/await은 프로미스를 기반으로 동작하지만, 프로미스의 then, catch, finally 메소드에 콜백 함수를 전달해서 비동기 처리 결과를 후속 처리할 필요 없이 마치 동기 처리처럼 프로미스를 사용할 수 있다.

async 함수

async는 함수 앞에 붙여서 비동기 함수로 만들어준다. async 함수는 항상 프로미스를 반환한다.

async function fetchData() {
  return "데이터 가져오기 완료";
}

fetchData().then(result => {
  console.log(result); // "데이터 가져오기 완료"
});

await 키워드

awaitasync 함수 안에서만 사용할 수 있으며, 프로미스가 해결될 때까지 기다린다.

await은 프로미스가 완료도리 때까지 기다린 후 결과값을 반환하고, 그 이후 코드를 실행한다.

awaiit은 비동기 작업이 완료될 때까지 코드의 실행을 일시 정지시키고, 그 작업이 끝나면 결과를 반환하는 형태로 동작한다.

async function fetchData() {
  let result = await new Promise((resolve) => setTimeout(() => resolve("데이터 처리 완료"), 1000));
  console.log(result);  // "데이터 처리 완료"
}

fetchData();

해당 예제에서 await은 프로미스가 해결될 때까지 기다린 후, 결과인 "데이터 처리 완료"를 반환한다. 이 때, 코드 흐름이 마치 동기 코드처럼 보이지만 실제로는 비동기 처리가 일어난다.

에러 처리

async/await에서 에러 처리는 try/catch를 사용한다.

async function fetchData() {
  try {
    let result = await new Promise((resolve, reject) => {
      let success = false;
      if (success) {
        resolve("작업 성공");
      } else {
        reject("작업 실패");
      }
    });
    console.log(result); // 작업 성공 (성공한 경우)
  } catch (error) {
    console.log("에러 발생:", error); // 작업 실패 (실패한 경우)
  }
}

fetchData();

async/await을 사용하면 비동기 코드의 가독성을 크게 향상시킬 수 있으며, 프로미스를 체이닝하는 것보다 더 직관적인 방식으로 비동기 작업을 처리할 수 있다.

0개의 댓글