Promise 클래스는 5가지 정적 메서드를 가지고 있다
여러 개의 프라미스를 동시에 실행시키고 모든 프라미스가 준비될 때까지 기다린다고 가정할 때
복수의 URL에 동시에 요청을 보내고 다운로드가 모두 완료된 후에 콘텐츠를 처리할 때 이런 상황이 발생한다
let promise = Promise.all([...promises...]);
Promise.all은 요소 전체가 프라미스인 배열(iterable 객체)을 받고 새로운 프라미스를 반환한다
배열 안 프라미스가 모두 처리되면 새로운 프라미스가 이행되는데, 배열 안 프라미스의 결괏값을 담은 배열이 새로운 프라미스의 result가 된다
Promise.all([
new Promise(resolve => setTimeout(() => resolve(1), 3000)), // 1
new Promise(resolve => setTimeout(() => resolve(2), 2000)), // 2
new Promise(resolve => setTimeout(() => resolve(3), 1000)) // 3
]).then(alert);
Promise.all은 3초 후에 처리되고, 반환되는 프라미스의 result는 배열 [1, 2, 3]이 된다
배열 result의 요소 순서는 Promise.all에 전달되는 프라미스 순서와 상응한다
Promise.all의 첫 번째 프라미스는 가장 늦게 이행되더라도 처리 결과는 배열의 첫 번째 요소에 저장된다
let urls = [
'https://api.github.com/users/jinju',
'https://api.github.com/users/baek',
'https://api.github.com/users/pearl'
];
// fetch를 사용해 url을 프라미스로 매핑
let requests = urls.map(url => fetch(url));
// Promise.all은 모든 작업이 이행될 때까지 기다림
Promise.all(requests)
.then(responses => responses.forEach(
response => alert(`${response.url}: ${response.status}`)
));
Promise.all([
new Promise((resolve, reject) => setTimeout(() => resolve(1), 1000)),
new Promise((resolve, reject) => setTimeout(() => reject(new Error("에러")), 2000)),
new Promise((resolve, reject) => setTimeout(() => resolve(3), 3000))
]).catch(alert); // Error
Promise.all에 전달되는 프라미스 중 하나라도 거부되면, Promise.all이 반환하는 프라미스는 에러와 함께 바로 거부된다
2초 후 두 번째 프라미스가 거부되면서 Promise.all 전체가 거부되고, .catch가 실행된다
거부 에러는 Promise.all 전체의 결과가 된다
프라미스가 하나라도 거부되면 Promise.all은 즉시 거부되고 배열에 저장된 다른 프라미스의 결과는 사라져버리고 이행된 프라미스의 결과도 무시된다
fetch를 사용해 호출 여러 개를 만들면, 그 중 하나가 실패하더라도 호출은 계속 일어난다
그렇더라도 Promise.all은 다른 호출을 더는 신경쓰지 않는다
프라미스가 처리되긴 하나 그 결과는 무시된다
프라미스에는 취소 개념이 없어서 Promise.all도 프라미스를 취소하지 않습니다
AbortController를 사용하면 프라미스 취소가 가능하긴 하지만 프라미스 API는 아니다
Promise.all(...)은 대개 프라미스가 요소인 iterable 객체(대부분 배열)를 받는다
그런데 프라미스가 아닌 객체가 배열을 구성하면, 요소가 그래도 결과 배열로 전달된다
Promise.all([
new Promise((resolve, reject) => {
setTimeout(() => resolve(1), 1000)
}),
2,
3
]).then(alert); // 1, 2, 3
그래서 이미 결과를 알고 있는 값은 Promise.all로 그냥 전달하면 된다
구식 브라우저는 폴리필이 필요하다
프라미스가 하나라도 거절되면 전체를 거절하는 Promise.all에 반해 Promise.allSettled는 모든 프라미스가 처리될 때 까지 기다린다
반환되는 배열은 다음과 같은 요소를 가진다
{status: "fulfilled", value: result}{status: "rejected", reason: error}let urls = [
'https://api.github.com/users/jinju',
'https://api.github.com/users/baek',
'https://no-such-url'
];
Promise.allSettled(urls.map(url => fetch(url)))
.then(results => { // (*)
results.forEach((result, num) => {
if (result.status == "fulfilled") {
alert(`${urls[num]}: ${result.value.status}`);
}
if (result.status == "rejected") {
alert(`${urls[num]}: ${result.reason}`);
}
});
});
fetch를 사용해 여러 사람의 정보를 가져올 때 여러 요청 중 하나가 실패해도 다른 요청 결과는 여전히 있어야 할 때 Promise.allSettled가 사용된다
[
{status: 'fulfilled', value: ...응답...},
{status: 'fulfilled', value: ...응답...},
{status: 'rejected', reason: ...에러 객체...}
]
Promise.allSettled를 사용하면 위 처럼 각 프라미스의 상태와 값 또는 에러를 받을 수 있다
Promise.all과 비슷하지만 가장 먼저 처리되는 프라미스의 결과(혹은 에러)를 반환한다
let promise = Promise.race(iterable);
Promise.race([
new Promise((resolve, reject) => setTimeout(() => resolve(1), 1000)),
new Promise((resolve, reject) => setTimeout(() => reject(new Error("에러")), 2000)),
new Promise((resolve, reject) => setTimeout(() => resolve(3), 3000))
]).then(alert); // 1
첫 번 째 프라미스가 가장 빨리 처리상태가 되기 때문에 첫 번째 프라미스의 결과가 result값이 된다
프라미스 메서드 Promise.resolve와 Promise.reject는 async/await이 생긴 이후로 쓸모 없어졌기 때문에 잘 사용되지 않는다
Promise클래스에는 5가지 정적 메서드가 있다
Promise.all(promises) : 모든 프라미스가 이행될 때 까지 기다렸다가 그 결괏값을 담은 배열을 반환한다. 주어진 프라미스 중 하나라도 실패하면 Promise.all은 거부되고, 나머지 프라미스의 결과는 무시된다Promise.allSettled(promises) : 최근에 추가된 메서드로 모든 프라미스가 처리될 때 까지 기다렸다가 그 결과(객체)를 담은 배열을 반환한다status : "fulfilled" 또는 "rejected"value 또는 reasonPromise.race(promises) : 가장 먼저 처리된 프라미스의 결과 또는 에러를 담은 프라미스를 반환한다Promise.resolve(value) : 주어진 값을 사용해 이행 상태의 프라미스를 만든다 Promise.reject(error) : 주어진 에러를 사용해 거부 상태의 프라미스를 만든다