이전 글
프로미스의 정적 메서드 알아보기
앞선 포스팅에서는, 프로미스 객체 프로토타입 메서드인 then, catch, finally에 대해 살펴봤다.
이번에는 프로미스의 5가지 정적 메서드를 예시와 함께 알아보자.
프로미스의 정적 메서드는 5가지가 있다.
- resolve
- reject
- all
- race
- allSettled
resolve, reject 메서드는 이전 포스팅에서 콜백에 넣어뒀던 인자와 유사하다.
const pr = Promise.resolve("Tom");
pr.then(data => console.log(data)) // "Tom"
// 위의 코드와 아래의 코드는 동일하기 동작한다.
const pr2 = new Promise((resolve, reject)=>resolve("Tom"));
pr2.then(data => console.log(data)) // "Tom"
reject도 똑같이 사용할 수 있다.
Promise.all
앞으로 살펴볼 all, race, allSettled 메서드는
모두 여러개의 비동기 작업을 병렬 처리할 때 사용한다.
먼저 Promise.all
const get = (url) => {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.send();
xhr.onload = () => {
if (xhr.status === 200) {
resolve(JSON.parse(xhr.response));
} else {
reject("Error!");
}
};
});
};
const url = "https://jsonplaceholder.typicode.com";
const pr1 = get(`${url}/posts/1`);
const pr2 = get(`${url}/posts/2`);
const pr3 = get(`${url}/posts/3`);
pr1.then((data) => console.log(data));
pr2.then((data) => console.log(data));
pr3.then((data) => console.log(data));
3가지 비동기 작업 pr1,pr2,pr3이 있다.
이 작업들은 비동기이므로, 실행 순서가 보장되지 않는다.
실행순서 1,2,3과는 달리 3,1,2 순으로 완료되었다.
그런데 만약 1,2,3의 비동기 작업이 모두 완료된 이후에!
다른 A라는 작업을 수행해야 한다면??
현재로서는 1,2,3의 작업 중 어떤 작업이 가장 나중에 끝날 지 예측할 수 없다.
이 때 Promise.all을 사용해서 병렬처리를 하고, 3가지 비동기 작업이 모두 끝난 후 A작업을 수행할 수 있다.
all 메서드의 인수로는 프로미스 객체를 담은 배열을 전달해주고, then을 통해서 처리해줄 수 있다.
const get = (url) => {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.send();
xhr.onload = () => {
if (xhr.status === 200) {
resolve(JSON.parse(xhr.response));
} else {
reject("Error!");
}
};
});
};
const url = "https://jsonplaceholder.typicode.com";
const pr1 = get(`${url}/posts/1`);
const pr2 = get(`${url}/posts/2`);
const pr3 = get(`${url}/posts/3`);
Promise.all([pr1, pr2, pr3]).then((data) => console.log(data));
console.log("End");
all 메서드를 통해 pr1,pr2,pr3가 끝난 resolve 값들의 배열을 전달 받아서
then 메서드에서 A작업을 수행할 수 있게 되었다.
또한 pr1의 결과는 배열 0번째, pr2의 결과는 1번에 담기므로,
각각의 비동기 작업이 언제 끝났는지에 관계 없이 결과의 순서가 유지된다.
다만, Promise.all은 모든 프로미스가 Resolve 되어야 한다.
배열의 프로미스 중 하나라도 Reject 된다면 즉시 종료되며,
이 에러 처리를 then.catch를 통해 처리해줘야 한다.
Promise.race
Promise끼리 레이스를 펼친다.
all 메서드처럼 프로미스를 담은 배열을 전달받는다.
전달받은 프로미스 중에 가장 먼저 끝난 프로미스의 결과만을 반환한다.
(= 주의. 가장 먼저 pending을 탈출한 결과만을 반환하므로 fullfilled / rejected 둘 다 가능하다.)
race 역시 프로미스가 reject 된다면, catch를 통해 처리해줘야 한다.
race 적용 예를 생각해보자.
특정 작업을 수행하는 방법이 A,B,C가 있다.
그러나, 어떤 작업이 가장 빨리 끝나는지 알 수 없다.
이때는 어떤 작업이던지 먼저 끝나기만 하면 된다.
하나라도 작업이 완료되었다면 다른 작업이 끝날 때 까지 기다릴 필요가 없다.
여기서 완료는 fullfilled이거나 rejected임을 의미한다.
이 상황에서는 race 메서드로 가장 빠른 결과를 가져올 수 있겠다.
사용 방법은 all과 동일하다.
Promise.race([Promise객체, Promise객체, Promise객체])
.then(data=>console.log(data));
Promise.allSettled
settled이란, 프로미스의 상태가 결정된 것을 의미한다.
즉, fullfilled 되었거나 rejected 된 모든 상태 = settled 되었다 라고 이해한다.
그렇다면, allSettled는 배열로 전달받은 프로미스들의 상태가 모두 결정되었음을 의미한다.
모든 상태가 결정되었다면, then을 이용해서 다음 작업을 진행할 수 있다!
all은 reject가 하나라도 결정되면, 작업을 중지하므로 allSettled가 출현했다.
allSettled이 all, race와 다른 점?
then에서 받은 배열을 보면, 각 인덱스에 promise 처리 결과 객체가 담겨있다.
allSettled의 결과를 출력해보면
이처럼 {status:"", value:""} 의 형태를 가진다.
왜 allSettled는 다르게 출력될까?
all, race의 then에서는 항상 fullfilled된 프로미스만 있다.
그러나, allSettled에서는 fullfilled, rejected 모두 가질 수 있다.
status 속성을 통해 rejected임을 알려줘야, 개발자가 rejected 프로미스에 대한 후속처리를 할 수 있기 때문이다.
현재 아직 해결하지 못한 문제는...
Promise 객체의 비동기 작업이 완료되기 전에 console.log("End")가 먼저 실행되던 문제다.
다음 마지막 비동기는 async/await이다.
이것을 이용하면, 비동기 작업을 동기적으로 기다려줄 함수를 작성할 수 있다.
그 전에 마이크로 태스크큐에 대해서 먼저 알아보자.
다음 글
'JavaScript > theory' 카테고리의 다른 글
[자바스크립트] 비동기 작업의 동기 처리를 위한 Async/Await (0) | 2021.08.22 |
---|---|
[자바스크립트] 마이크로 태스크 큐와 프로미스 (0) | 2021.08.22 |
[자바스크립트] 프로미스 객체 (0) | 2021.08.22 |
[자바스크립트] 비동기로 데이터 가져오기, 콜백 헬 (0) | 2021.08.22 |
[자바스크립트] 비동기 작업, 이벤트 루프와 태스크 큐 (1) | 2021.08.22 |