17강

프로미스(Promise)

3 조회 1

Promise의 세 가지 상태와 then/catch/finally 체이닝을 이해한다. Promise.all, Promise.race, Promise.allSettled 등 정적 메서드와 fetch API를 활용한 실전 패턴을 익힌다.

Promise — 콜백 헬의 해결책

Promise는 비동기 작업의 최종 완료(또는 실패)와 그 결과값을 나타내는 객체입니다. ES6에서 도입되었으며, 콜백 헬을 체이닝 방식으로 해결합니다.

Promise의 세 가지 상태

Pending(대기)  → 비동기 작업 진행 중
Fulfilled(이행) → 작업 성공, resolve() 호출됨
Rejected(거부)  → 작업 실패, reject() 호출됨

// 상태는 한 번만 변경됨 (Pending → Fulfilled 또는 Rejected)

Promise 생성

// 기본 구조
const promise = new Promise((resolve, reject) => {
  // 비동기 작업 수행
  setTimeout(() => {
    const success = true;
    if (success) {
      resolve("작업 완료!"); // 성공 시
    } else {
      reject(new Error("작업 실패!")); // 실패 시
    }
  }, 1000);
});

// 즉시 이행/거부
const resolved = Promise.resolve(42);  // 즉시 fulfilled
const rejected = Promise.reject(new Error("에러")); // 즉시 rejected

then / catch / finally

fetchUser(1)
  .then(user => {
    console.log("유저:", user);
    return fetchOrders(user.id); // 다음 Promise 반환 → 체이닝
  })
  .then(orders => {
    console.log("주문:", orders);
    return orders[0]; // 일반 값 반환도 가능
  })
  .then(firstOrder => {
    console.log("첫 주문:", firstOrder);
  })
  .catch(error => {
    // 체인 어디서든 에러가 나면 여기서 처리
    console.error("에러 발생:", error.message);
  })
  .finally(() => {
    // 성공/실패 관계없이 항상 실행
    setLoading(false);
    hideSpinner();
  });

// 콜백 헬 vs Promise 체이닝 비교
// 콜백: 가로로 길어짐 (들여쓰기 증가)
// Promise: 세로로 읽기 좋음 (체이닝)

fetch API — 가장 많이 쓰는 Promise

// GET 요청
fetch("https://api.example.com/users/1")
  .then(response => {
    if (!response.ok) {
      throw new Error(`HTTP 에러: ${response.status}`);
    }
    return response.json(); // JSON 파싱도 비동기!
  })
  .then(user => {
    console.log(user);
  })
  .catch(error => {
    console.error("요청 실패:", error);
  });

// POST 요청
fetch("https://api.example.com/users", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ name: "Kim", age: 30 })
})
  .then(res => res.json())
  .then(data => console.log("생성됨:", data))
  .catch(err => console.error(err));

Promise 정적 메서드

// Promise.all — 모두 완료될 때까지 대기 (하나라도 실패하면 즉시 reject)
Promise.all([
  fetchUser(1),
  fetchProducts(),
  fetchCategories()
]).then(([user, products, categories]) => {
  // 셋 다 완료됐을 때만 실행
  renderPage(user, products, categories);
}).catch(err => {
  // 하나라도 실패하면 catch
  console.error(err);
});

// Promise.allSettled — 모두 완료 대기, 결과 상태 포함 (ES2020)
Promise.allSettled([
  fetchUser(1),
  fetchProducts(),
  fetchSomethingThatFails()
]).then(results => {
  results.forEach(result => {
    if (result.status === "fulfilled") {
      console.log("성공:", result.value);
    } else {
      console.log("실패:", result.reason);
    }
  });
});

// Promise.race — 가장 먼저 완료된 것만 반환
Promise.race([
  fetch("https://api1.example.com/data"),
  fetch("https://api2.example.com/data"), // 백업 서버
]).then(response => response.json())
  .then(data => console.log("가장 빠른 응답:", data));

// Promise.any — 가장 먼저 성공한 것 반환 (모두 실패해야 reject)
Promise.any([
  tryServer1(),
  tryServer2(),
  tryServer3(),
]).then(result => console.log("첫 번째 성공:", result))
  .catch(() => console.error("모두 실패"));

Promise 에러 처리 패턴

// 특정 단계에서만 에러 처리 후 계속 진행
fetchUser(1)
  .then(user => fetchOrders(user.id))
  .catch(err => {
    console.warn("주문 로드 실패, 빈 배열 사용:", err);
    return []; // 에러를 복구하고 체인 계속
  })
  .then(orders => renderOrders(orders)); // 빈 배열이라도 실행됨

// 에러 타입 구분
fetchData()
  .catch(error => {
    if (error.name === "NetworkError") {
      return retryRequest();
    }
    if (error.status === 401) {
      redirectToLogin();
    }
    throw error; // 처리 못 하면 다음 catch로 전달
  })

Promise 직접 만들기 — 유틸리티 패턴

// setTimeout을 Promise로 래핑
function delay(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

// 사용
delay(1000).then(() => console.log("1초 후"));

// 재시도 로직
function fetchWithRetry(url, maxRetries = 3) {
  return fetch(url).catch(err => {
    if (maxRetries === 0) throw err;
    return delay(1000).then(() => fetchWithRetry(url, maxRetries - 1));
  });
}

관련 검색어  ·  Promise 사용법, then catch finally, fetch API, Promise.all allSettled, Promise 체이닝, 자바스크립트 비동기 처리

채용정보
공지사항
인사이트
MY