모던 자바스크립트 Deep Dive | 프로미스
45장 프로미스
들어가며
예전에 부트캠프에서 Promise
와 async/await
를 간단히 정리한 적이 있었는데, 이번에는 딥다이브 책을 공부하면서 다시 한 번 자세히 정리해보고자 한다.
자바스크립트에서 비동기 처리를 다루는 대표적인 패턴은 콜백이었다. 하지만 콜백 패턴은
- 콜백 지옥(Callback Hell)
- 에러 처리의 어려움
이라는 단점이 있었다.
이를 극복하기 위해 ES6에서 Promise
가 도입되었고, 이후 비동기 프로그래밍의 표준으로 자리 잡게 되었다.
1. 프로미스의 생성
프로미스는 비동기 처리 상태와 결과를 관리하는 객체다.
const promise = new Promise((resolve, reject) => {
// 비동기 처리 로직
if (/* 성공 */) resolve('success');
else reject('error');
});
프로미스는 3가지 상태(state)를 가진다.
- pending: 비동기 처리 수행 전
- fulfilled: 성공적으로 완료 (resolve 호출)
- rejected: 실패 (reject 호출)
한 번 settled(fulfilled/rejected) 상태가 되면 더 이상 다른 상태로 변하지 않는다.
2. 프로미스의 후속 처리 메서드
프로미스는 처리 결과에 따라 후속 작업을 정의할 수 있는 메서드를 제공한다.
-
then
- 두 개의 콜백을 인수로 받는다. (성공 시, 실패 시)
- 항상 새로운 프로미스를 반환한다.
promise .then((result) => console.log(result)) .catch((err) => console.error(err));
-
catch
- 실패(rejected) 상태만 처리한다.
- 모든
then
이후에 배치하면 체인 전체에서 발생한 에러를 처리할 수 있다.
promise.catch((err) => console.error(err));
-
finally
- 성공/실패 여부와 관계없이 무조건 실행된다.
promise.finally(() => console.log("작업 종료"));
프로미스의 에러 처리
then
의 두 번째 인자로 에러 처리를 할 수도 있지만, 일반적으로는 catch
사용이 권장된다.
이유는 가독성이 좋고, then
내부에서 발생한 에러까지 한 번에 잡을 수 있기 때문이다.
마이크로태스크 큐
프로미스 후속 처리 메서드의 콜백은 태스크 큐가 아닌 마이크로태스크 큐에 저장된다.
setTimeout(() => console.log(1), 0);
Promise.resolve()
.then(() => console.log(2))
.then(() => console.log(3));
실행 순서는 2 → 3 → 1
이다.
마이크로태스크 큐가 태스크 큐보다 우선순위가 높다는 점을 주의하자.
3. 프로미스 체이닝
프로미스를 활용하면 기존 콜백 패턴의 단점인 콜백헬을 개선할 수 있다.
const url = "https://jsonplaceholder.typicode.com";
promiseGet(`${url}/posts/1`)
.then(({ userId }) => promiseGet(`${url}/users/${userId}`))
.then((userInfo) => console.log(userInfo))
.catch((err) => console.error(err));
체이닝을 통해 비동기 작업을 순차적으로 연결할 수 있고, 가독성이 훨씬 좋아진다.
단, 여전히 콜백 자체를 완전히 제거할 수는 없기 때문에 ES8부터는 async/await
을 사용한다. 그래도 프로미스를 기본으로 하고 있으니 잘 이해하자.
4. 프로미스의 정적 메서드
Promise
객체는 정적 메서드를 제공한다.
-
Promise.resolve / Promise.reject
즉시 이행되거나 거부되는 프로미스를 반환한다.
-
Promise.all 여러 개의 비동기 처리를 병렬로 처리한다.
Promise.all([req1(), req2(), req3()]) .then((results) => console.log(results)) // [1,2,3] .catch(console.error);
- 모든 프로미스가
fulfilled
가 되어야 완료된다. - 하나라도
rejected
면 즉시 실패한다.
- 모든 프로미스가
-
Promise.race
여러 프로미스 중 가장 먼저 처리된 결과를 반환한다.
-
Promise.allSettled
모든 프로미스가 settled 상태가 될 때까지 기다린 후 결과 배열을 반환한다.
5. fetch
fetch
함수는 HTTP 요청을 전송하는 Web API다.
fetch("https://jsonplaceholder.typicode.com/posts/1")
.then((res) => res.json()) // Response 객체 → JSON 변환
.then((data) => console.log(data))
.catch((err) => console.error(err));
- 항상
Promise
를 반환한다. - 응답(Response)을
json()
,text()
등의 메서드로 변환해야 한다(역직렬화).
마무리
프로미스는 단순한 문법 요소가 아니라, 자바스크립트의 비동기 처리 패러다임을 바꾼 핵심 개념이다. 콜백 패턴의 단점을 보완하면서 코드의 가독성과 에러 처리를 한층 개선해 주었다.
예로는 Promise.all
을 활용한 병렬 요청, fetch
를 통한 API 통신, 그리고 async/await
과 함께 자연스럽게 사용된다.