🫠
Promise.allで失敗したものだけ検知したい
結論
Promise.allSettled()
を使いましょう
Promise.allSettled()
とは
複数のPromise
を同時に実行しそれぞれについて成功、失敗と結果、エラー内容を返してくれます。
どれかが失敗しても全てのPromise
が完了するまで待機します。
TypeScriptの場合、返ってくる型は下記のようになります(抜粋)
{
status: "fulfilled"
value: T
} |
{
status: "rejected"
reason: any
}[]
各結果に対して、status === 'fulfilled'
ならば実行結果がvalue
として、status === 'rejected'
ならば失敗理由がreason
として取得できます。
Promise.all
との違い
Promise.all
の場合はPromise
のうちどれか一つでも失敗するとPromise.all
自体が失敗したような感じになりcatch
節に入ります。
失敗するPromise
を含んで実行した場合の結果の違いは下記のようになります。
// 失敗
const promise1 = new Promise((resolve, reject) => {
reject()
})
// 成功
const promise2 = new Promise((resolve, reject) => {
resolve('resolve')
})
// => error
Promise.all([promise1, promise2]).then(() => {
console.log("done")
}).catch(() => {
console.log("error")
})
// => done
Promise.allSettled([promise1, promise2]).then(() => {
console.log("done")
}).catch(() => {
console.log("error")
})
使い分け
MDNにあるように、各Promiseに依存があるかないかなどで判断します。
お互いに依存せずに正常に完了する場合や、各プロミスの結果を常に知りたい場合
Promise.allSettled
タスクがお互いに依存している場合や、タスクのいずれかが拒否されたときにすぐに拒否したい場合
Promise.all
MDN
Discussion
neverthrowライブラリだとエラーのみを抽出してくれる Result.combineWithAllErrorsがあります。
これで少しデモも作ってみました。
また、バニラだと型のnarrowingでやや手数が多いのですが、そのときのワークアラウンドも作ってみました。
簡単ですが、以上です。