프라미스 API
프라미스 API
Promise 클래스에는 5가지 정적 메서드가 있습니다. 이번 시간에는 5가지의 메서드를 알아보도록 하겠습니다.
Promise.all
여러 개의 프라미스들을 동시에 실행시킵니다. 모든 프라미스가 준비가 될 때까지 기다립니다.
문법
let promise = Promise.all([..promises...]);
예시
let promise = Promise.all([
new Promise(resolve=>setTimeout(()=>resolve(1),3000)),
new Promise(resolve=>setTimeout(()=>resolve(2),2000)),
new Promise(resolve=>setTimeout(()=>resolve(3),1000)),
]).then(response=>{
console.log(response);
});
결과: 3초 후 [1,2,3]
위의 코드를 보면 3번째 프라미스가 1초 후 완료, 2번째 프라미스가 2초 후 완료, 3번째 프라미스가 3초 후 완료됩니다.
실행 순서와 상관없이 첫번쨰 프라미스 결과는 첫 번째 배열에 저장됩니다.
작업해야 할 데이터가 담긴 배열을 프라미스 배열로 매핑하고, 이 배열을 Promise.all로 감싸는 트릭은 자주 사용됩니다.
URL이 담긴 배열을 fetch를 써서 처리하는 예시
let urls = [
'https://api.github.com/users/iliakan',
'https://api.github.com/users/remy',
'https://api.github.com/users/jeresig'
];
// 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에 전달되는 프라미스들 중 하나라도 거부되면, Promise.all이 반환하는 프라미스는 에러와 함께 바로 거부됩니다.
Error가 날때
Promise.all([
new Promise((resolve,reject)=>setTimeout(()=>resolve(1),1000)),
new Promise((resolve,reject)=>setTimeout(()=>reject(new Error('에러발생')),3000)),
new Promise((resolve,reject)=>setTimeout(()=>resolve(1),2000))
]).then(requests=>{
requests.forEach(re=>console.log(req));
})
결과: Error: 에러발생
프라미스가 하나라도 거부되면 Promise.all은 즉시 거부되고 배열에 저장된 다른 프라미스의 결과를 완전히 잊어버립니다. 이미 이행된 프라미스 결과들도 무시됩니다.
+이터러블 객체가 아닌 "일반" 값도 Promise.all(iterable)에 넘길 수 있습니다.
Promise.all(..)은 대부분 프라미스가 요소인 이터러블 객체를 받습니다. 그런데 프라미스가 아닌 객체가 배열을 구성하면 그 요소가 '그대로' 결과 배열로 전달됩니다.
Promise.all([
new Promise(resolve=>setTimeout(()=>resolve(1),1000)),
3,
2
]).then(alert);
결과: 1,3,2
Promise.allSettled
Promise.all은 프라미스가 하나라도 거절되면 전체를 거절합니다. 하지만 Promise.allSettled는 모든 프라미스가 처리될 때까지 기다립니다. 반환되는 배열은 다음과 같은 요소를 갖습니다. 즉 하나의 프로미스가 거절돼도 전체를 거절하지 않습니다.
- 응답이 성공한 경우: {status:"fulfilled", value: result}
- 에러가 발생한 경우: {status:"rejected", reason: error"}
let urls = [
'https://api.github.com/users/iliakan',
'https://api.github.com/users/remy',
'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}`);
}
});
});
위의 코드에서 (*)로 표시한 줄의 results는 다음과 같습니다.
[
{status: 'fulfilled', value: ...응답...},
{status: 'fulfilled', value: ...응답...},
{status: 'rejected', reason: ...에러 객체...}
]
Promise.allSettled를 사용하면 각 프라미스의 상태와 값 또는 에러를 받을 수 있습니다.
Promise.race
Promise.race는 Promise.all과 비슷합니다. 하지만 가장 먼저 처리된 프라미스의 결과(또는 에러)를 반환합니다.
예시
Promise.race([
new Promise(resolve=>setTimeout(()=>resolve(1),3000)),
new Promise(resolve=>setTimeout(()=>reject(new Error("에러발생")),2000)),
new Promise(resolve=>setTimeout(()=>resolve(3),1000)),
]).then(result=>console.log(result));
결과: 1
첫 번째 프라미스가 가장 빨리 결과를 반환하기 때문에 result의 값이 됩니다. 두 번째 프라미스에서 에러가 발생해도 이미 result값이 나타난 순간에는 다른 프라미스의 결과 또는 에러는 모두 무시됩니다.
Promise.resolve/reject
프라미스 메서드 Promise.resolve와 Promise.reject는 async/await 문법이 생긴 이후로 쓸모가 없어져서 근래에는 거의 사용하지 않는다고 합니다.
하지만 저는 아직 async/await에 대해서 자세히 모르고 Promise의 5가지 함수들을 알기 위해 작성해봅니다.
Promise.resolve
Promise.resolve(value)는 결괏값이 value인 이행 상태 프라미스를 생성합니다.
아래의 코드와 동일한 역할을 수행합니다.
let promise = new Promise(resolve=>resolve(value));
Promise.resolve는 호환성을 위해 함수가 프라미스를 반환하도록 해야 할 때 사용할 수 있습니다.
Promise.reject
Promise.reject(error)는 결괏값이 error인 거부 상태 프라미스를 생성합니다.
아래 코드와 동일한 역할을 수행합니다.
let promise = new Promise((resolve,reject)=>reject(error));
실무에서 이 메서드를 쓸 일은 거의 없다고 합니다.