⛓️
Promise 내부 — then()이 Microtask Queue에 들어가는 과정
Promise의 3가지 상태와 thenable 체이닝의 실행 메커니즘
const p = new Promise((resolve, reject) => {
// executor: 동기적으로 즉시 실행
resolve('done');
});
p.then(value => console.log(value)); // 'done' — 하지만 지금 바로가 아니라 Microtask에서
상태 전이
pending → fulfilled (resolve 호출)
pending → rejected (reject 호출 또는 throw)
한 번 전이하면 다시 바뀌지 않는다 (immutable). resolve를 두 번 호출해도 첫 번째만 유효.
then은 새 Promise를 반환한다
fetch('/api')
.then(res => res.json()) // Promise 반환
.then(data => data.name) // 또 Promise 반환
.catch(err => fallback); // 또 Promise 반환
.then()이 새 Promise를 반환하기 때문에 체이닝이 가능하다. 각 then의 콜백은 이전 Promise가 fulfilled될 때 Microtask Queue에 들어간다.
async/await와의 관계
// 이 두 코드는 동일하다:
async function getData() {
const res = await fetch('/api');
const data = await res.json();
return data;
}
function getData() {
return fetch('/api')
.then(res => res.json());
}
await는 Promise.then()의 문법적 설탕이다. await 뒤의 코드는 then() 콜백으로 변환된다. 내부적으로 generator + Promise 조합으로 구현.
에러 처리
// ❌ catch 없으면 에러가 삼켜진다 (Unhandled Promise Rejection)
fetch('/api').then(res => res.json());
// ✅ 반드시 catch
fetch('/api').then(res => res.json()).catch(err => console.error(err));
// ✅ async/await에서는 try/catch
try {
const data = await fetch('/api');
} catch (err) {
console.error(err);
}
핵심 포인트
1
new Promise(executor)의 executor는 동기적으로 즉시 실행된다
2
resolve() 호출 → pending → fulfilled 전이 (한 번만, 불변)
3
then()에 등록된 콜백이 Microtask Queue에 들어감
4
async/await는 Promise + generator의 문법적 설탕
사용 사례
API 호출 체이닝 — fetch().then().then().catch() 패턴 이해
Promise.all/race/allSettled — 병렬 비동기 제어