Promise.all, Promise.allSettled

ES
비고
Tags
promise
 

Promise.all 과 Promise.allSettled의 차이점

  • Promise.all() will technically reject as soon as one of the functions passed in the array rejects.
  • Promise.allSettled() will never reject - instead it will wait for all functions passed in the array to either resolve or reject.
 

Promise.all

 
 

Promise.allSettled

항상 resolved가 반환된다.

  • Promise.allSettled는 항상 resolved를 반환한다 : https://stackoverflow.com/questions/72074735/catch-is-not-handling-rejection-of-promise-in-case-multiple-javascript-promise
    • 배열 형태로 반환되며, 배열 안에 들어오는 값은 아래의 두 종류 중 하나로 구성된다.
      • { status: “fulfilled” & value: ‘resolve 값’ }
      • { status: “rejected” & reason: ‘reject 값’ }
    • 따라서 reject 케이스와 reason을 보고싶다면 배열 내부 요소를 일일이 까서 확인해야한다.
    • ⚠️
      따라서 하나라도 실패한 경우에 예외처리를 해야한다면, Promise.all 을 사용하자

reject reason 설정방법

Promise.reject(’사유’)를 해야 reason에 적힌다.
 
eslint에선 아래와 같이 Promise.reject 시에 new Error를 넘길 것을 추천하는데, 이렇게 하면 allsettled의 결과값을 출력해보면 reason에서 텍스트를 찾아볼 수 없다..-_-;;;
/*eslint prefer-promise-reject-errors: "error"*/ Promise.reject(new Error("something bad happened")); Promise.reject(new TypeError("something bad happened")); new Promise(function(resolve, reject) { reject(new Error("something bad happened")); }); var foo = getUnknownValue(); Promise.reject(foo);
reject 추천 처리 방식
 

reason에 값이 쓰이지 않는 모습

const asyncTest = async() => { throw new Error('reject test'); } const settledTest = async()=>{ const result = await Promise.allSettled([asyncTest()]); console.log("result", result) } settledTest(); // 에러에 적은 텍스트가 reason으로 들어갈 줄 알았는데 {}로 조회되는 모습 // [LOG]: "result", [{ // "status": "rejected", // "reason": {} // }]

reason에 값이 적히는 모습

const asyncTest = async() => { return Promise.reject("reject test") } const settledTest = async()=>{ const result = await Promise.allSettled([asyncTest()]); console.log("result", result) } settledTest(); // 에러 메세지가 reason에 제대로 조회되는 모습 // [LOG]: "result", [{ // "status": "rejected", // "reason": "reject test" // }]

의문 (어디선 되고, 어디선 안되고)

eslint에서 권장하는 방법대로 사용했을 때 reason이 나오는 경우가 있고, 안나오는 경우가 있다.
환경의 차이인지 잘 모르겠다.
const asyncTest = async() => { return Promise.reject( new Error('reject test')); } const settledTest = async()=>{ const result = await Promise.allSettled([asyncTest()]); console.log("result", result) } settledTest();
  • reason과 콜스택이 잘 조회되는 모습
codesandbox.io 에선 reason이 잘 나오는 모습
  • reason에 {} 로만 들어가 있는 모습
typescript playground 에선 reason이 안나오는 모습
typescript playground 에선 reason이 안나오는 모습
notion image
const asyncTest = async() => { return Promise.reject( new Error('reject test')); } const settledTest = async()=>{ const result = await Promise.allSettled([ asyncTest().catch((e)=>console.log("catch", e)) ]); console.log("result", result) } settledTest(); // [LOG]: "catch", reject test // [LOG]: "result", [{ // "status": "fulfilled", // "value": undefined // }]
이렇게 하면 reject가 되면서 catch에선 new Error 했던 텍스트를 잡아볼 수 있겠다라고 생각했는데, catch에서 에러 메세지를 받아볼 순 있지만 status는 fulfilled로 조회된다.

return Promise.reject()를 반환해도 catch 문에서 잘 잡힌다.

💡
promise.allsettled와 같이 쓰이는 경우엔 promise.reject로 실패 처리 할 것을 추천함. ⇒ promise.allsettled에선 status: reject, reason: 블라블라 잘 잡히고, 기존의 try catch로 잡던 부분에서도 reject 시에 catch 문에서 잘 잡히기 때문이다.
별도의 콜스택이 필요한 상황이 아니라면, promise.reject로만 예외처리를 해도 상황에 따른 처리를 할 수 있다.
const asyncTest = async() => { return Promise.reject('reject test'); } const settledTest = async()=>{ try{ await asyncTest() }catch{ console.log("reject인데 catch에서 잡히나?"); } } settledTest(); // [LOG]: "reject인데 catch에서 잡히나?" // => Promise.reject()를 반환해도 catch 문에서 잘 잡힌다.

typescript

fulfilled와 rejected 시의 오브젝트 형태가 다르다.
  • fulfilled : { status: ‘fulfilled’, value: any }
  • rejected : { status: ‘rejected’, reason: any }
따라서 어떤 오브젝트인지 식별을 해줘야 타입에서 에러가 나오지 않는다.
 
rejected 오브젝트 활용을 예시로 들면 아래와 같다.
const errors = results.filter( (result): result is PromiseRejectedResult => result.status === 'rejected' ) // errors는 PromiseRejectedResult[] 타입으로 식별되므로 reason에 접근하여도 타입에러가 나오지 않는다.