Promise.all과 Promise.race 실무 활용 사례

문제 상황

대시보드 페이지에서 사용자 정보, 통계 데이터, 최근 활동 로그 등 5개의 API를 호출해야 했다. 순차적으로 호출하니 초기 로딩 시간이 3초 이상 걸렸다.

Promise.all 적용

const fetchDashboard = async () => {
  try {
    const [user, stats, logs, notifications, settings] = await Promise.all([
      fetch('/api/user'),
      fetch('/api/stats'),
      fetch('/api/logs'),
      fetch('/api/notifications'),
      fetch('/api/settings')
    ]);
    
    return {
      user: await user.json(),
      stats: await stats.json(),
      logs: await logs.json(),
      notifications: await notifications.json(),
      settings: await settings.json()
    };
  } catch (error) {
    console.error('Dashboard fetch failed:', error);
  }
};

병렬 처리로 로딩 시간을 1.2초로 단축했다. 하지만 하나의 API가 실패하면 전체가 실패하는 문제가 있었다.

부분 실패 허용하기

필수 데이터와 선택 데이터를 구분해서 처리했다.

const fetchDashboardSafe = async () => {
  const results = await Promise.all([
    fetch('/api/user').catch(e => null),
    fetch('/api/stats').catch(e => null),
    fetch('/api/logs').catch(e => null)
  ]);
  
  return results.filter(r => r !== null);
};

Promise.race 활용

API 타임아웃 구현에 Promise.race를 사용했다.

const fetchWithTimeout = (url, timeout = 5000) => {
  return Promise.race([
    fetch(url),
    new Promise((_, reject) => 
      setTimeout(() => reject(new Error('Timeout')), timeout)
    )
  ]);
};

결론

Promise.all은 성능 개선에 효과적이지만 에러 핸들링을 신중하게 설계해야 한다. 각 Promise에 catch를 붙이거나, allSettled 폴리필을 고려할 필요가 있다.