배경
배치 작업에 작업 실패 시 경보를 추가하는 작업을 진행했다.
그런데 Promise.allSettled() 메서드를 실행하면서 이 구문을 try catch로 묶어 처리하는 코드를 발견했다.
Promise.allSettled()는 병렬 작업 중 에러가 발생하더라도 호출부에서 에러가 throw 되지 않는다.
비동기 작업 처리를 위해 흔히 사용되는 Promise.all()과 Promise.allSettled()에 대해 알아보자.
Promise.all()
Promsie.all()은 일반적으로 다음 코드를 실행하기 전에, 서로 연관된 비동기 작업 여러 개가 모두 실행되어야 할 때 사용된다.
결과값으로 실행된 프로미스들의 결과값을 담은 배열을 반환한다.
결과값의 순서는 매개변수로 전달된 프로미스 순서와 동일하다.
// 비동기 함수 예시
function fetchUser(id) {
return new Promise(resolve => {
setTimeout(() => {
resolve({ id, name: `User${id}` });
}, 1000 * id); // id에 따라 응답 속도를 다르게
});
}
// 여러 유저 정보 가져오기
async function getUsers() {
const promises = [fetchUser(1), fetchUser(2), fetchUser(3)];
try {
// 모든 요청이 끝날 때까지 기다림
const results = await Promise.all(promises);
console.log("모든 유저 정보:", results);
// 모든 유저 정보: [ {id:1, name:"User1"}, {id:2, name:"User2"}, {id:3, name:"User3"} ]
} catch (error) {
console.error("에러 발생:", error);
}
}
getUsers();
Promise.all()은 인자로 들어온 프로미스 중 하나라도 거부 당하면 (에러 발생)
Promise.all은 즉시 거부하여 catch 구문으로 넘어가게 된다.
다만 여기서 주의할 점은 Promise.all()이 reject 상태가 되었다고 해서, 인자의 프로미스 작업들이 모두 중단되는 것은 아니다.
각 작업들은 비동기적으로 여전히 진행되고, Promise.all()만 에러를 반환하며 catch 구문으로 넘어가는 것이다.
Promise.allSettled()
이와 달리 Promise.allSettled()는 인자로 들어온 프로미스들을 모두 실행하거나, 거부한 후
그 프로미스 결과 객체들을 담은 배열을 반환한다.
일반적으로 서로의 성공/실패 여부와 관계없이 여러 비동기 작업을 실행해야 하거나,
항상 각 프로미스의 결과를 알고 싶을 때 사용한다.
(Promise.all()은 서로 연관된 작업을 수행하거나, 하나라도 거부 당했을 때 즉시 거부하고 싶을 때 적합하다.)
반환된 결과 객체는 status 프로퍼티를 갖는다.
status 값에 따라서 값이 "fulfilled" 라면 value 프로퍼티를
"rejected" 라면 reason 프로퍼티를 갖는다.
value, reason을 통해서 프로미스가 어떻게 실행/거부 됐는지 알 수 있다.
Promise.allSettled([
Promise.resolve(33),
new Promise((resolve) => setTimeout(() => resolve(66), 0)),
99,
Promise.reject(new Error("an error")),
]).then((values) => console.log(values));
// [
// {status: "fulfilled", value: 33},
// {status: "fulfilled", value: 66},
// {status: "fulfilled", value: 99},
// {status: "rejected", reason: Error: an error}
// ]
async 함수로 표현하면 아래와 같다.
async function successTask() {
return "성공 결과"; // resolve("성공 결과")와 같음
}
async function failTask() {
throw new Error("실패 발생!"); // reject(new Error(...))와 같음
}
async function run() {
const tasks = [successTask(), failTask(), Promise.resolve(123), Promise.reject("단순 실패")];
const results = await Promise.allSettled(tasks);
results.forEach((result, index) => {
if (result.status === "fulfilled") {
console.log(`Task ${index + 1} 성공:`, result.value);
} else {
console.log(`Task ${index + 1} 실패:`, result.reason);
}
});
}
run();
/*
Task 1 성공: 성공 결과
Task 2 실패: Error: 실패 발생!
Task 3 성공: 123
Task 4 실패: 단순 실패
*/
결론
Promise.allSettled()를 사용하는 부분에 경보를 붙이는 코드는
try catch를 사용하지 않고,
Promise.allSettled() 결과 배열에서 status가 rejected인 객체를 필터링하여
그에 따라 경보가 작동하도록 했다.
참고 자료
Promise.all() - JavaScript | MDN
이 메서드는 여러 프로미스의 결과를 집계할 때 유용하게 사용할 수 있습니다. 일반적으로 다음 코드를 계속 실행하기 전에 서로 연관된 비동기 작업 여러 개가 모두 이행되어야 하는 경우에 사
developer.mozilla.org
'Node.js > JavaScript' 카테고리의 다른 글
[개념 정리] 자바스크립트 prototype & prototypal 상속 (0) | 2023.09.18 |
---|---|
[JS문법] 이스케이프 시퀀스 종류 정리 (0) | 2023.08.09 |
[js 메서드] 배열.find() (1) | 2023.06.18 |
[js 내장 객체] Map (4) | 2023.06.16 |
[js 내장 객체] Set (1) | 2023.06.16 |