비동기 함수의 대표적 예시인 setTimeout 함수에 대해 생각해보자.
let timeout = setTimeout(() => {
console.log('Hello world");
}, 1000);
위 코드는 1000ms 라는 조건 이후에 () => { console.log('Hello world"); } 부분이 바로 실행된다. 여기에는 문제가 있는데, 바로 비동기 처리 상태 및 처리 결과를 따로 저장할 수가 없다는 점이다.
timeout 변수는 고유한 타이머 ID를 반환하기 때문에 처리 결과를 보관하는 것이 아니다.
이러한 단점을 보완하기 위해 만들어진 것이 바로 Promise이다. Promise를 한 줄로 설명하자면 다음과 같다.
Promise는 실행은 하되, 결괏값을 나중에 쓸 수 있다.
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('fulfilled');
}, 1000)
})
// ...
// do something...
// ...
promise.then((v) => console.log(v)); // fulfilled
Promise 생성자 함수는 비동기 처리를 수행할 콜백 함수인 resolve와 reject 함수를 콜백 함수의 인수로 전달받는다.
콜백 함수 내 비동기 처리가 성공하면 resolve 함수를 호출하고, 실패하면 reject 함수를 호출한다.
이렇게 resolve되거나 reject된 결괏값을 변수에 저장해놓고 있다가 나중에 사용할 수 있다는 점이 Callback과 다른 Promise의 특징이라고 할 수 있다.
다음과 같이 여러 개의 데이터를 서버로부터 get하는 상황에 대해서도 생각해보자.
const p1 = axios.get('서버주소1');
const p2 = axios.get('서버주소2');
const p3 = axios.get('서버주소3');
Promise.all 메서드는 여러 개의 비동기 처리를 모두 병렬 처리할 때 사용한다.
Promise.all([p1, p2, p3])
.then(console.log)
.catch(console.error);
Promise.all 메서드는 모든 프로미스가 fulfilled 상태가 될 때 종료된다. 만약 프로미스 중 하나에 대해 에러가 발생한다면 이전의 모든 처리 결과를 무시하고 즉시 rejected 상태가 된다는 특징이 있다.
Promise.allSettled 메서드는 Promise.all과 유사하나 성공/실패 여부와 관계없이 모든 처리 결과를 배열로 반환한다는 특징이 있다.
Promise.allSettled([p1, p2, p3])
.then(console.log);
fulfilled 상태인 경우 비동기 처리 상태를 나타내는 status 프로퍼티와 처리 결과를 나타내는 value 프로퍼티를 갖는다. reject 상태인 경우 비동기 처리 상태를 나타내는 status 프로퍼티와 에러를 나타내는 reason 프로퍼티를 갖는다.따라서 Promise.allSettled 메서드 이용 시 실패한 것만 필터링해서 다시 요청을 보낼 수 있다는 장점 때문에 Promise.all 대신 사용할 것을 권장하고 있다.