Promise.allSettled 폴리필 구현하기

문제 상황

배치 작업에서 여러 외부 API를 호출한 뒤, 성공/실패 여부를 각각 로깅해야 했다. Promise.all을 사용하면 하나라도 실패할 경우 catch로 빠져버려서 나머지 결과를 확인할 수 없었다.

// 기존 코드 - 하나라도 실패하면 전체 실패
Promise.all([
  fetchUser(1),
  fetchUser(2),
  fetchUser(3)
])
.then(results => console.log(results))
.catch(err => console.error(err)); // 여기로 빠짐

해결 방법

Promise.allSettled가 ES2020에 제안되어 있지만, 현재 브라우저에서는 지원하지 않는다. 직접 구현했다.

function allSettled(promises) {
  return Promise.all(
    promises.map(promise =>
      Promise.resolve(promise)
        .then(value => ({ status: 'fulfilled', value }))
        .catch(reason => ({ status: 'rejected', reason }))
    )
  );
}

각 Promise를 try-catch로 감싸서 무조건 fulfilled 상태로 만드는 방식이다. 결과 객체에 status와 value/reason을 담아 반환한다.

사용 예시

allSettled([
  fetchUser(1),
  fetchUser(2),
  fetchUser(999) // 존재하지 않는 유저
]).then(results => {
  results.forEach((result, index) => {
    if (result.status === 'fulfilled') {
      logger.info(`User ${index}: ${result.value.name}`);
    } else {
      logger.error(`User ${index}: ${result.reason.message}`);
    }
  });
});

모든 결과를 받아서 개별적으로 처리할 수 있게 되었다. 배치 작업에서 일부 실패가 전체 프로세스를 멈추지 않도록 개선되었다.