두 파일을 동시에 읽다가 첫 번째가 실패했다. Promise.all의 catch가 실행됐으니 두 번째도 멈췄을까? 로그를 조금 더 지켜보면 두 번째 작업은 끝난다. 묶음의 결과가 실패한 것과 이미 시작한 개별 작업을 취소한 것은 다르다.
Promise.all의 거부는 작업 취소가 아니다
도식의 REJECTED는 묶음 Promise의 결과를 뜻한다. 실패 신호가 나온 뒤에도 이미 실행 중인 다른 작업의 선은 DONE까지 이어지므로, 중단이 필요하면 각 작업이 이해하는 별도 취소 수단이 있어야 한다.
Promise.all([a, b])은 a와 b가 모두 이행되면 순서대로 값을 담은 배열로 이행한다. 둘 중 하나가 거부되면 반환한 묶음 Promise는 그 이유로 거부된다. 하지만 이 동작은 입력 Promise에 ‘중단’ 신호를 보내지 않는다.
아래 코드는 실제 파일이나 네트워크를 사용하지 않고, 서로 다른 시간에 끝나는 두 작업을 만든다. 첫 번째는 빠르게 실패하고 두 번째는 나중에 완료된다.
async function main() {
const failed = new Promise((_, reject) => {
setTimeout(() => {
console.log("A failed");
reject(new Error("A unavailable"));
}, 10);
});
const slow = new Promise((resolve) => {
setTimeout(() => {
console.log("B finished");
resolve("B result");
}, 30);
});
try {
await Promise.all([failed, slow]);
} catch (error) {
console.log("all rejected:", error.message);
}
await slow;
}
main();A failed
all rejected: A unavailable
B finished마지막 await slow는 두 번째 작업의 완료를 관찰하기 위해 넣었다. 이것이 작업을 다시 시작하는 것은 아니다. slow는 Promise.all에 전달하기 전에 이미 만들어졌다. 첫 번째 실패로 묶음의 결과는 사용할 수 없지만, 두 번째 타이머는 계속 살아 있다.
첫 실패 뒤에도 완료 로그가 나오는지 어떻게 확인할까?
실제 코드에서 ‘전체 실패’ 직후 완료 로그가 늦게 찍히면 재시도 로직이 중복 실행됐다고 오해하기 쉽다. 먼저 각 작업의 시작·성공·실패 로그에 같은 요청 식별자와 개별 작업 이름을 붙여 시간 순서를 확인하자. 민감한 응답 본문이나 인증 헤더를 로그에 남길 필요는 없다.
테스트에서는 빠른 실패와 느린 성공을 의도적으로 만들고, 묶음의 catch가 먼저 실행돼도 느린 작업의 완료 효과가 남는지 검사한다. 만약 느린 작업이 DB 수정이나 메시지 발송처럼 부작용을 가진다면, 첫 실패 뒤에도 그 부작용이 생길 수 있다는 점까지 테스트해야 한다. catch 안에서 다시 같은 묶음을 바로 재시도하면 이전 작업과 새 작업이 겹칠 수 있기 때문이다.
모든 결과가 필요한가, 실제 취소가 필요한가
성공·실패를 작업별로 모두 모아 보고 싶다면 Promise.allSettled를 검토한다. 하나가 거부되어도 나머지의 최종 상태를 기다려 { status: "fulfilled", value } 또는 { status: "rejected", reason } 형태로 받는다. 다만 이것도 취소 기능은 아니다.
반대로 한 작업이 실패하면 다른 작업도 멈춰야 하는 요구라면 각 작업이 지원하는 취소 방법을 별도로 설계해야 한다. 예를 들어 fetch는 신호를 받을 수 있지만, 이미 서버에서 처리된 요청까지 되돌리는 보장은 아니다. 서버 작업에는 중복 요청에 안전한 식별자와 보상·정리 정책이 필요할 수 있다. ‘빨리 오류를 알려 주기’와 ‘남은 작업을 멈추기’를 같은 요구로 취급하지 않는 것이 핵심이다.
핵심 요약: 묶음의 실패와 개별 작업의 종료를 나누자
Promise.all은 입력 중 하나가 거부되면 반환한 Promise를 거부하지만 다른 입력을 자동 취소하지 않는다. 작업별 최종 결과가 필요하면 allSettled를, 실제 중단이 필요하면 해당 작업의 취소 계약을 살펴야 한다. 부작용이 있는 병렬 작업을 재시도하기 전에는 이전 작업이 정말 끝났는지 확인하자.
작성자
기초 개념을 구현과 검증, 실제 운영 판단까지 연결해 기록합니다.

