Promise.any() 그리고 Promise.race()

June·2024년 8월 28일
1
post-thumbnail

Promise.any()Promise.race() 는 둘 다 여러 Promise를 받아 병렬로 실행하고, 가장 빨리 완료된 Promise의 결과를 반환하는 메서드입니다.

Promise.race()

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.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)
  ]);
};

사용 사례

  • 다중 데이터 소스 조회: 여러 데이터베이스나 API에서 동일한 정보를 조회할 때, 가장 빠르게 응답하는 소스의 결과를 사용할 수 있습니다.
  • 리소스 할당: 여러 리소스 중 사용 가능한 첫 번째 리소스를 할당할 때 유용합니다.
  • 분산 시스템에서의 데이터 조회: 여러 노드에 분산된 데이터를 조회할 때, 가장 빠르게 응답하는 노드의 결과를 사용할 수 있습니다.
  • failover 메커니즘: 주 서비스가 실패할 경우 백업 서비스로 신속하게 전환할 수 있습니다.

결론

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()는 여러 시도 중 하나라도 성공하면 되는 경우에 더 적합합니다.

0개의 댓글

관련 채용 정보