← JavaScript 강의 목록으로
🤝
비동기
중급 · 선수: 14_콜백과_타이머

15. Promise

Promise 는 "미래의 어느 시점에 완료될 작업의 결과를 담는 상자"입니다. 세 가지 상태가 있습니다.

Promisethencatch비동기
소요 시간
약 1.5시간
난이도
📊 중급
선수 조건
🎯 단원 14
결과물
Promise 는 "미래의 어느 시점에 완료될 작업의 결과를 담는 상자"입니다. 세 가지 상태가 있습니다.

이 강의에서 배우는 것

  • 1Promise 의 세 가지 상태(pending, fulfilled, rejected)를 안다.
  • 2`new Promise` 로 직접 Promise 를 생성할 수 있다.
  • 3`then`, `catch`, `finally` 로 결과를 처리한다.
  • 4체이닝으로 콜백 지옥을 평탄화할 수 있다.
  • 5`Promise.all`, `Promise.race` 의 차이를 안다.

소개

Promise 는 "미래의 어느 시점에 완료될 작업의 결과를 담는 상자"입니다. 세 가지 상태가 있습니다.

핵심 개념

1. Promise 란?

Promise 는 "미래의 어느 시점에 완료될 작업의 결과를 담는 상자"입니다. 세 가지 상태가 있습니다.

  • pending: 아직 끝나지 않음
  • fulfilled: 성공, 값이 있음
  • rejected: 실패, 이유(에러)가 있음
javascript
const p = new Promise((resolve, reject) => {
  setTimeout(() => resolve(42), 100);
});

`resolve` 를 호출하면 fulfilled, `reject` 를 호출하면 rejected 가 됩니다. 한 번 정해진 상태는 바뀌지 않습니다.

2. then / catch / finally

javascript
p.then((value) => console.log(value))
 .catch((err) => console.error(err))
 .finally(() => console.log("끝"));

`then` 의 콜백에서 반환한 값은 다음 `then` 의 인자로 들어갑니다. 에러가 발생하면 가까운 `catch` 가 잡습니다.

3. 체이닝

콜백 지옥 예제를 Promise 로 다시 쓰면 평탄해집니다.

javascript
step("1").then(() => step("2")).then(() => step("3"));

`then` 안에서 Promise 를 반환하면 그것이 완료될 때까지 다음 `then` 이 기다립니다.

4. Promise.all / Promise.race

  • `Promise.all([p1, p2, ...])`: 모두 성공해야 성공, 하나라도 실패하면 실패. 결과는 배열.
  • `Promise.race([p1, p2, ...])`: 가장 먼저 결정(성공/실패)된 결과를 채택.
  • `Promise.allSettled`: 모두 끝날 때까지 기다리고, 각각의 상태 객체 배열을 돌려줌.

핵심 예제

파일다루는 내용
01_new_promise.jsnew Promise 로 직접 만들기
02_then_catch.jsthen/catch/finally 사용
03_chaining.js체이닝으로 순차 실행
04_all_race.jsPromise.all / Promise.race

src/01_new_promise.js

javascript
/**
 * new Promise 로 비동기 작업을 표현합니다.
 */
const promise = new Promise((resolve, reject) => {
  const ok = Math.random() > 0.3;
  setTimeout(() => {
    if (ok) resolve("성공!");
    else reject(new Error("실패..."));
  }, 200);
});

promise
  .then((value) => console.log("결과:", value))
  .catch((err) => console.error("에러:", err.message));

src/02_then_catch.js

javascript
/**
 * then / catch / finally 의 흐름을 보여줍니다.
 */
function fetchUser(id) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (id <= 0) reject(new Error("잘못된 ID"));
      else resolve({ id, name: "지민" });
    }, 100);
  });
}

fetchUser(1)
  .then((user) => console.log("user:", user))
  .catch((err) => console.error(err.message))
  .finally(() => console.log("요청 종료"));

fetchUser(-1)
  .then((user) => console.log(user))
  .catch((err) => console.error("에러:", err.message))
  .finally(() => console.log("두 번째 요청 종료"));

src/03_chaining.js

javascript
/**
 * Promise 체이닝으로 비동기 단계를 순차 실행합니다.
 */
function step(name, ms) {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log(`${name} 완료`);
      resolve(name);
    }, ms);
  });
}

step("A", 100)
  .then((prev) => step(`B(after ${prev})`, 100))
  .then((prev) => step(`C(after ${prev})`, 100))
  .then((last) => console.log("최종:", last));

src/04_all_race.js

javascript
/**
 * Promise.all 과 Promise.race 비교.
 */
function delay(ms, value) {
  return new Promise((resolve) => setTimeout(() => resolve(value), ms));
}

Promise.all([delay(100, "A"), delay(200, "B"), delay(150, "C")]).then((values) => {
  console.log("all:", values);
});

Promise.race([delay(100, "X"), delay(50, "Y"), delay(80, "Z")]).then((value) => {
  console.log("race winner:", value);
});

자주 하는 실수

  1. `then` 에서 값을 반환하지 않아 다음 `then` 에서 undefined 를 받음.
  2. `catch` 없이 사용해 unhandled rejection 발생.
  3. `Promise.all` 에 하나라도 실패하면 전체 실패라는 점을 잊음.
  4. `new Promise` 안에서 throw 한 에러는 자동으로 reject 가 됨을 모름.
  5. Promise 가 즉시 실행됨을 모르고 "lazy" 라고 생각.

FAQ

Q1. resolve/reject 는 즉시 호출해도 되나요?

됩니다. 그래도 then 콜백은 비동기로 실행됩니다.

Q2. catch 와 then 의 두 번째 인자 차이?

then(onFul, onRej) 의 onRej 는 같은 then 의 onFul 에서 던진 에러는 잡지 못합니다. catch 가 더 안전합니다.

Q3. Promise 안에 Promise 를 반환하면?

자동으로 풀려서 then 다음 단계로 값이 전달됩니다.

과제

  1. setTimeout 기반 `delay(ms)` Promise 함수.
  2. Promise.all 로 여러 작업을 병렬 실행하는 코드.

homework/README.md

## 1. delay 함수 `delay(ms)` 가 ms 밀리초 후 resolve 되는 Promise 를 돌려주도록 작성하세요.

## 2. 병렬 합산 세 개의 비동기 숫자 값을 Promise.all 로 받아 합계를 출력하세요.

답안은 `answer/` 디렉터리를 참고하세요.

homework/answer/homework_01.js

javascript
/**
 * 주어진 시간만큼 기다린 뒤 resolve 되는 Promise.
 * @param {number} ms 대기 밀리초
 * @returns {Promise<void>}
 */
function delay(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

console.log("시작");
delay(500).then(() => console.log("0.5초 경과"));

homework/answer/homework_02.js

javascript
/**
 * 세 개의 비동기 숫자를 병렬로 받아 합을 출력합니다.
 */
function asyncNumber(n, ms) {
  return new Promise((resolve) => setTimeout(() => resolve(n), ms));
}

Promise.all([asyncNumber(10, 100), asyncNumber(20, 150), asyncNumber(30, 80)])
  .then((nums) => {
    const sum = nums.reduce((a, b) => a + b, 0);
    console.log("합계:", sum);
  });

다음 단원

[16_async_await](../16_async_await/) — Promise 를 더 쉽게 쓰는 문법

예제 코드 / 강의 자료

전체 강의 자료와 예제 코드는 GitHub에서 자유롭게 받아볼 수 있습니다.

GitHub에서 보기 ↗