Promise.all과 Promise.race로 병렬 API 호출 최적화하기
문제 상황
대시보드 페이지에서 사용자 정보, 주문 내역, 알림 목록 등 5개의 API를 순차적으로 호출하고 있었다. 각 API가 평균 200~300ms 소요되다 보니 전체 로딩 시간이 1.5초를 넘어갔다.
function loadDashboard() {
fetch('/api/user').then(user => {
this.setState({ user });
return fetch('/api/orders');
}).then(orders => {
this.setState({ orders });
return fetch('/api/notifications');
}).then(notifications => {
this.setState({ notifications });
});
}
해결 방법
API들이 서로 의존성이 없다는 점을 활용해 Promise.all로 병렬 처리했다.
function loadDashboard() {
Promise.all([
fetch('/api/user').then(r => r.json()),
fetch('/api/orders').then(r => r.json()),
fetch('/api/notifications').then(r => r.json()),
fetch('/api/settings').then(r => r.json()),
fetch('/api/stats').then(r => r.json())
]).then(([user, orders, notifications, settings, stats]) => {
this.setState({ user, orders, notifications, settings, stats });
}).catch(err => {
console.error('Dashboard load failed:', err);
});
}
로딩 시간이 300ms 정도로 줄어들었다. 가장 느린 API 하나의 응답 시간만큼만 기다리면 되기 때문이다.
Promise.race 활용
타임아웃 처리가 필요한 경우 Promise.race도 유용했다.
function fetchWithTimeout(url, timeout = 5000) {
return Promise.race([
fetch(url),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), timeout)
)
]);
}
하나의 API라도 실패하면 전체가 실패하는 Promise.all의 특성 때문에, 에러 핸들링을 각 fetch마다 해주는 것도 고려해야 한다.