API 병렬 호출 : Promise.all, Promise.allSettled, Promise.race 비교

들어가며
이번 주 리액트 스터디에서 API 병렬 호출과 관련한 추가 요구사항을 받았다. 주어진 요구사항은 다음과 같다.
3개의 API를 병렬 호출할 것
3개의 API 요청이 모두 성공한 뒤 데이터가 화면에 반영될 것
실패 시 각 API마다 다른 에러 UI를 보여줄 것
이 요구사항을 해결하기 위해서 Promise.all
을 사용해서 병렬 호출을 처리했다. 하지만 이 과정에서 Promise.allSettled
을 알게 되어서 더 깊이 이해하기 위해서 이번 글을 작성했다.
이번 글에서는 Promise.all
, Promise.allSettled
, Promise.race
를 비교하고, 각각의 사용 사례를 살펴보려고 한다.
Promise.all : 모든 요청이 성공해야 할 때
개념
순회 가능한 프로미스를
Promise.all
의 인자로 넘기고 모든 프로미스를 이행한 뒤 값을 배열 형태로 반환한다.배열에 담긴 프로미스 중 단 하나라도 실패하면, 첫 번째 거부 이유로 전체가 거부된다. 즉, 다른 프로미스의 이행 여부는 알 수가 없다.
요청 성공 시 예제
function fetchData(id: string, delay: number) {
return new Promise((resolve) => {
setTimeout(() => resolve(`✅ Data from ${id}`), delay);
});
}
async function getAllData() {
const results = await Promise.all([
fetchData("API 1", 3000), // 3초 후 응답
fetchData("API 2", 1000), // 1초 후 응답
fetchData("API 3", 2000), // 2초 후 응답
]);
console.log("📌 반환된 결과:", results); // 모든 API가 성공한 경우에만 결과 출력
}
getAllData();
요청 실패 시 예제
실패 테스트를 위해서 fetchData
함수에 shouldFail
플래그를 추가했다.
function fetchData(id, delay, shouldFail = false) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (shouldFail) {
reject(`❌ Failed to fetch data from ${id}`);
} else {
resolve(`✅ Data from ${id}`);
}
}, delay);
});
}
async function getAllData() {
try {
const results = await Promise.all([
fetchData("API 1", 3000), // 3초 후 응답 성공
fetchData("API 2", 1000, true), // 1초 후 실패
fetchData("API 3", 2000), // 2초 후 응답 성공
]);
console.log("📌 반환된 결과:", results);
} catch (error) {
console.error("❌ 하나라도 실패하면:", error); // 하나라도 실패하면 전체가 실패
}
}
getAllData();
사용 케이스
여러 API에서 데이터를 가져와서 한 번에 처리할 때
모든 요청이 성공해야 하는 경우
단점
하나라도 실패하면 전체 요청이 실패한다.
다시 모든 API를 호출해야 하는 부담이 있다.
Promise.allSettled : 일부 요청이 실패해도 결과가 필요할 때
개념
모든 프로미스의 상태를 배열로 반환한다.
일부 요청이 실패해도 모든 요청의 결과를 확인할 수 있다.
요청 실패 시 예제
위의 코드에서 Promise.all
을 Promise.allSettled
로 변경하자, 각 프로미스의 상태와 결과를 개별로 확인할 수 있었다.
const results = await Promise.allSettled([
fetchData("API 1", 3000), // 3초 후 응답 성공
fetchData("API 2", 1000, true), // 1초 후 실패
fetchData("API 3", 2000), // 2초 후 응답 성공
]);
console.log("📌 반환된 결과:", results);
사용 케이스
일부 데이터만이라도 활용하고 싶을 때
여러 API 요청을 병렬로 실행하면서 성공한 요청만 필터링할 때
단점
- 개별 요청의 상태와 값을 직접 확인하고 추가로 처리해야 한다.
Promise.race : 가장 빠른 응답이 필요할 때
개념
성공이나 실패 여부와 상관없이 가장 먼저 완료되는 프로미스의 결과를 반환한다.
요청 성공 시 예제
const results = await Promise.race([
fetchData("API 1", 3000), // 3초 후 응답 성공
fetchData("API 2", 1000), // 1초 후 실패
fetchData("API 3", 2000), // 2초 후 응답 성공
]);
console.log("📌 반환된 결과:", results);
사용 케이스
가장 빠르게 응답하는 데이터를 우선적으로 사용하고 싶을 때
단점
나머지 요청이 완료되지 않더라도 가장 먼저 완료된 응답만 반환한다.
마무리하며
API 병렬 요청을 처리하는 방법으로 Promise.all
, Promise.allSettled
, Promise.race
를 비교해 보았다. 각 메서드의 API 요청의 성공과 실패를 다루는 방식을 다르므로, 네트워크 요청을 보다 효율적으로 관리하기 위해서 적절한 프로미스 메서드를 선택해야겠다.
참고 링크
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise/race
Subscribe to my newsletter
Read articles from yarnmi directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
