ES6 Promise.all 오류 처리 방식 정리

문제 상황

대시보드 화면에서 5개의 API를 동시에 호출해야 했다. Promise.all을 사용했는데, 하나의 API만 실패해도 전체가 reject되어 정상적으로 받아온 데이터마저 사용할 수 없었다.

const fetchData = async () => {
  try {
    const [users, orders, stats, notifications, settings] = await Promise.all([
      fetch('/api/users'),
      fetch('/api/orders'),
      fetch('/api/stats'),
      fetch('/api/notifications'),
      fetch('/api/settings')
    ]);
  } catch (error) {
    // 하나만 실패해도 여기로
    console.error(error);
  }
};

해결 방법

각 Promise를 catch로 감싸서 실패해도 reject되지 않도록 처리했다.

const fetchData = async () => {
  const results = await Promise.all([
    fetch('/api/users').catch(err => ({ error: err })),
    fetch('/api/orders').catch(err => ({ error: err })),
    fetch('/api/stats').catch(err => ({ error: err })),
    fetch('/api/notifications').catch(err => ({ error: err })),
    fetch('/api/settings').catch(err => ({ error: err }))
  ]);

  const [users, orders, stats, notifications, settings] = results;
  
  // 각각의 성공/실패 여부 확인
  if (users.error) {
    console.error('Users API failed:', users.error);
  }
};

더 나은 방법

반복되는 코드를 줄이기 위해 헬퍼 함수를 만들었다.

const settle = promise => 
  promise
    .then(data => ({ status: 'fulfilled', data }))
    .catch(error => ({ status: 'rejected', error }));

const fetchData = async () => {
  const results = await Promise.all([
    settle(fetch('/api/users')),
    settle(fetch('/api/orders')),
    settle(fetch('/api/stats')),
    settle(fetch('/api/notifications')),
    settle(fetch('/api/settings'))
  ]);

  results.forEach((result, index) => {
    if (result.status === 'fulfilled') {
      // 성공 처리
    } else {
      // 실패 로깅
    }
  });
};

정리

Promise.all은 하나라도 실패하면 전체가 실패한다. 부분적인 실패를 허용하려면 각 Promise에 catch를 추가하거나, 래퍼 함수를 사용해야 한다. ES2020의 Promise.allSettled를 사용하면 이런 패턴이 표준으로 제공되지만, 아직은 직접 구현해서 써야 한다.

ES6 Promise.all 오류 처리 방식 정리