new Promise(executor);프로미스는 비동기(혹은 지연된) 처리의 상태와 결과 값을 나타낸다. Promise 생성자는 비동기 로직을 구현한 함수 executor를 인수로 전달받는데, executor는 resolve과 reject 함수를 인수로 전달받는다. executor를 전달하지 않으면 오류가 발생한다.
new Promise();
// 💥 Uncaught TypeError: Promise resolver undefined is not a function사용자는 프로미스의 인자 executor를 직접 정의하여 비동기 로직을 구현할 수 있다.
(resolve, reject) => {}- 비동기 처리가 성공한 경우 받고 싶은 값
successValue을 인자로 넘겨resolve를 호출한다. 생성된 객체의[[PromiseState]]는fulfilled가 되고[[PromiseResult]]는successValue가 된다. - 비동기 처리가 실패한 경우 받고 싶은 값
errorValue를 인자로 넘겨reject를 호출한다. 생성된 객체의[[PromiseState]]는rejected가 되고[[PromiseResult]]는errorValue가 된다. resolve나reject를 호출하지 않으면 프로미스는 영원히pending상태에 머무른다.
const get = url => new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.send();
xhr.onload = () => {
if (xhr.status === 202) resolve(JSON.parse(xhr.response));
else reject(new Error(xhr.status));
}
});프로미스 객체는 일반 객체에 대해 추가적으로 [[PromiseState]] 내부 슬롯을 가진다. [[PromiseState]]는 프로미스 객체의 상태를 값으로 가진다.
프로미스 객체의 상태는 비동기 처리의 상태를 의미한다. 다음 세 가지 상태는 상호배타적으로 일단 상태를 옮기면 더이상 변하지 않는다.
pending: 기본값으로 비동기 처리가 아직 수행되지 않은 상태를 나타낸다.settled상태로 변화할 수 있다. 이때[[PromiseResult]]는 의미가 없다.- settled: 비동기 처리가 수행이 완료된 상태를 나타낸다.
fulfilled또는rejected상태이다.fulfilled: 비동기 처리가 성공으로 완료되었음을 나타낸다.resolve함수를 호출하여pending에서 변화한다.rejected: 비동기 처리가 실패로 완료되었음을 나타낸다.reject함수를 호출하여pending에서 변화한다.
프로미스 객체는 일반 객체에 대해 추가적으로 [[PromiseResult]] 내부 슬롯을 가진다. [[PromiseResult]]는 사용자가 정의한 비동기 처리의 결과 값(executor 내부에서 resolve 혹은 reject를 호출했을 때 넘긴 인자)을 값으로 가진다. [[PromiseState]]가 pending이 아닐 때만 의미가 있다.
기본적으로 자바스크립트 값이면 모두 가능하지만 reject를 호출하는 경우 Error 객체를 생성하여 전달할 것을 권고한다. 상태가 rejected인 프로미스 객체는 해당 값을 throw하고 실행을 중단시키기 때문이다.
new Promise((_, reject) => reject(1)); // 💥 Uncaught (in promise) 1우리가 원하는 값은 비동기 처리가 완료되었을 때 프로미스가 가진 결과 값이다. 프로미스는 프로미스가 가진 결과 값을 처리할 수 있는 콜백을 인자로 전달받는 프로토타입 메서드를 제공한다. 각 프로토타입 메서드는 프로미스 객체를 반환하므로, 프로미스 체이닝(promise chaining)을 사용할 수 있다.
new Promise(executor).then(onFulfilled, onRejected);ouFulfilled: 프로미스가fulfilled상태이면 호출할 함수이다. 인자로 프로미스의 결과 값이 전달된다. 함수가 아니라 값을 전달하면 항등 함수((x) => x)로 변환된다.onRejected: 프로미스가rejected상태이면 호출할 함수를 전달한다. 인자로 프로미스의 결과 값이 전달된다. 함수가 아니라 값을 전달하면 thrower 함수((x) => { throw x; })로 변환된다.- 반환값: 실행된 콜백 함수가 반환하는 프로미스 객체이다. 프로미스가 아니면 해당 값을
resolve한 프로미스를 반환하는데, 값을 throw하면 해당 값을reject한 프로미스를 반환한다.
new Promise(resolve => resolve(1)).then(value => console.log(value)); // 1
new Promise((_, reject) => reject(1)).then(undefined, (reason) => console.log(reason)); // 1new Promise(executor).catch(onRejected);then(null, onRejected)와 같다. 단, then(onFulfilled, onRejected)를 사용하면 onRejected는 onFulfilled에서 값을 던졌을 때 해당 오류를 처리할 수 없으므로 catch를 따로 두는 것이 좋다.
new Promise(executor).then(onFulfilled).catch(onRejected);new Promise(executor).finally(onFinally)onFinally: 프로미스의 성공이나 실패 상태에 상관없이 한 번 호출된다. 인자로 프로미스의 결과 값이 전달된다.then,catch메서드에서 공통적인 로직이 있을 때 유용한다.- 반환값: 실행된 콜백 함수가 반환하는 프로미스 객체이다. 프로미스가 아니면 해당 값을
resolve한 프로미스를 반환하는데, 값을 throw하면 해당 값을reject한 프로미스를 반환한다.
Promise.resolve(value);인자로 전달받은 값을 resolve하는 프로미스 객체를 반환한다.
new Promise(resolve => resolve(1));
Promise.resolve(1);위 두 예제는 동일하게 동작한다.
Promise.reject(reason);인자로 전달받은 값을 reject하는 프로미스 객체를 반환한다.
new Promise((_, reject) => reject(1)).catch(v => console.log(v)); // 1
Promise.reject(1).catch(v => console.log(v)); // 1위 두 예제는 동일하게 동작한다.
Promise.all(iterable);- 이터러블을 인자로 받는다. 이때 프로미스가 아닌 요소는
Promise.resolve로 프로미스로 래핑한다. 인자가 빈 배열이면 동기적으로 실행되지만 그렇지 않으면 비동기적으로 실행된다. - 프로미스를 반환한다.
- 인자로 전달된 모든 프로미스를 병렬로 실행하고 모든 프로미스가
fulfilled상태가 되면resolve된 처리 결과를 배열로 가진 프로미스를 반환한다. - 프로미스 중 하나라도
rejected상태가 되면 나머지가fulfilled상태가 되는 것을 기다리지 않고 해당reject된 처리 결과를 가진 프로미스를 반환한다.
- 인자로 전달된 모든 프로미스를 병렬로 실행하고 모든 프로미스가
Promise.race(iterable)- 이터러블을 인자로 받는다. 이때 프로미스가 아닌 요소는
Promise.resolve로 프로미스로 래핑한다. - 가장 먼저 settled(
fulfilled나rejected) 상태가 된 프로미스를 반환한다. 단, 인자가 빈 배열이면pending상태의 프로미스를 반환한다.
Promise.allSetteld(iterable);- 이터러블을 인자로 갖는다.
- 모든 프로미스가 settled(
fulfilled나rejected) 상태가 되면 해당 상태와 결과 값을 요소로한 배열을 가진 프로미스를 반환한다.
Promise
.allSettled([Promise.resolve(1), Promise.reject(2)])
.then(console.log);
/*
[
{status: 'fulfilled', value: 1},
{status: 'rejected', reason: 2}
]
*/executor 내부에서 오류가 발생하거나 throw로 값을 던지면 해당 값을 reject한다. executor 주위에 암시적으로 try...catch문이 있어 에러를 잡고 reject처럼 다루는 것이다.
new Promise(() => {
throw new Error('에러 발생!');
}).catch(e => console.log(e)); // Error: 에러 발생!
new Promise(() => {
throw 1;
}).catch(reason => console.log(reason)); // 1프로미스의 프로토타입 메서드 then, catch, finally는 인자로 받은 콜백이 반환하는 프로미스를 반환하거나 값을 반환한 경우 해당 값을 resolve 혹은 reject한 프로미스를 반환하므로, 에러를 다시 던져 다른 핸들러에서 처리하도록 할 수 있다.
new Promise((_, reject) => {
reject('에러 발생!');
}).catch(reason => {
if (error instanceof AuthError) handleAuthError();
else throw reason;
}).catch(reason => {
if (error instanceof NotFoundError) handleNotFoundError();
else throw reason;
}).catch(reason => handleError());ES8에 도입된 키워드 async와 await를 사용하면 동키 코드처럼 프로미스를 사용할 수 있다.
async function get(url) {
const res = await fetch(url);
const data = await res.json();
return res;
}async/await에 대해서는 async와 await를 참고한다.