Promise.any() 와 Promise.race() 는 둘 다 여러 Promise를 받아 병렬로 실행하고, 가장 빨리 완료된 Promise의 결과를 반환하는 메서드입니다.
Promise.race()는 reject나 resolve 상태에 상관없이 가장 먼저 settled(해결된) 상태가 되는 Promise의 결과를 반환합니다.
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
const timeout = (ms: number) => new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), ms));
const fakeFetch = async (url: string, _delay: number) => {
await delay(_delay);
return `Response from ${url}`;
};
const fetchWithTimeout = async (
url: string,
delay: number,
_timeout: number,
) => {
return Promise.race([
fakeFetch(url, delay),
timeout(_timeout)
]);
};
function bootstrap() {
fetchWithTimeout('https://example.com', 1000, 500)
.then((res) => console.log(res))
.catch((err) => console.error(err));
}
bootstrap(); // Timeout
타임아웃(500ms)이 페치 지연 시간(1000ms)보다 짧기 때문에, timeout 함수가 fakeFetch 함수보다 먼저 완료됩니다. 따라서 Promise.race는 timeout 함수의 결과를 선택합니다.
Promise.any()는 여러 Promise 중 가장 먼저 성공적으로 완료되는 Promise의 결과를 반환합니다. 모든 Promise가 실패하면 AggregateError를 throw합니다.
위의 예시에서 fetchWithTimeout 함수의 Promise.race() 만 Promise.any() 로 변경해보겠습니다.
const fetchWithTimeout = async (
url: string,
delay: number,
_timeout: number,
) => {
return Promise.any([
fakeFetch(url, delay),
timeout(_timeout)
]);
};
function bootstrap() {
fetchWithTimeout('https://example.com', 1000, 500)
.then((res) => console.log(res))
.catch((err) => console.error(err));
}
bootstrap(); // Response from https://example.com
타임아웃(500ms)이 페치 지연 시간(1000ms)보다 짧기 때문에, timeout 함수가 fakeFetch 함수보다 먼저 완료됩니다. 그러나 Promise.any()는 가장 먼저 성공하는 promise의 결과를 선택하기 때문에 fakeFetch() 의 결과를 선택합니다.
만약 아래 처럼 모든 promise가 실패하면 Promise.any()는 'All promises were rejected' (AggregateError
) 을 throw 합니다.
const fetchWithTimeout = async (
url: string,
delay: number,
_timeout: number,
) => {
return Promise.any([
timeout(_timeout),
timeout(_timeout)
]);
};
Promise.race()와 Promise.any()는 둘 다 여러 Promise를 병렬로 실행하고 가장 빨리 완료된 Promise의 결과를 반환한다는 점에서 유사합니다. 하지만 그 동작 방식에는 중요한 차이가 있습니다
Promise.race()는 가장 먼저 settled 상태가 되는 Promise의 결과를 반환합니다. 이는 완료(resolve) 되든 실패(reject) 하든 상관없이 첫 번째로 완료되는 Promise의 결과를 그대로 반환합니다. 이 특성은 타임아웃 구현 등에 유용하게 사용될 수 있습니다.
Promise.any()는 가장 먼저 성공적으로 완료(resolve)되는 Promise의 결과만을 반환합니다. 이는 실패(reject)하는 Promise는 무시하고 첫 번째로 성공하는 Promise의 결과를 기다립니다. 만약 모든 Promise가 실패하면 AggregateError를 throw합니다.
이 두 메서드의 차이점을 이해하고 적절히 활용하면, 다중 데이터 소스 조회, 리소스 할당, 분산 시스템에서의 데이터 조회, failover 메커니즘 구현 등 다양한 상황에서 효과적인 비동기 로직을 구현할 수 있습니다.
Promise.race()는 모든 결과(성공/실패)에 대해 즉각적인 응답이 필요한 경우에, Promise.any()는 여러 시도 중 하나라도 성공하면 되는 경우에 더 적합합니다.