Chapter 06

Promise.allの親戚たち

いーちゃん
いーちゃん
2021.08.15に更新

Promise.all

まずは復習、Promise.all
引数にPromiseの配列を渡し、そのPromiseの実行がすべて正常に完了するもしくは1つでも失敗するとresolve/rejectされます。
返り値(thenの引数)には各Promiseの返り値が指定順に渡され、エラー理由(catchの引数)は一番最初にrejectされたPromiseのものが渡されます。

// p1, p2, p3, ...はPromiseオブジェクト
await Promise.all([p1, p2, p3, ...])
// [p1の返り値, p2の返り値, p3の返り値, ...]

Promise.allSettled

続いて、Promise.allSettled
親戚というくらいなので引数は同じ。
そのPromiseの実行がすべて終了する = すべてのPromiseの成功/失敗が決まるとresolve/rejectされます。
Promise.allとの違いは、たとえ1つPromiseがrejectされても処理が続くことです。
返り値には各Promiseの状態と返り値("fulfilled""rejected")もしくは理由が指定順に渡されます。
Promise.allSettled自身は基本的にすべてresolveされるので、中身がrejectされたこともthen内で判定します。エラーにはなりません。

await Promise.allSettled([p1, p2, p3, ...])
/*
  [{
     status: p1の状態,
     value: p1の返り値,
   }, {
     status: p2の状態,
     value: p2の返り値
   }, {
     status: p3の状態,
     reason: p3が失敗した理由
   },
   ...
  ] 
*/

Promise.any

ES2021で追加された新キャラです。
引数のPromiseの実行が1つでも正常に完了するもしくはすべて失敗するとresolve/rejectされます。
1つのPromiseがresolveされると、あとのPromiseの結果はすべて無視されます。
返り値には一番最初にresolveされたPromiseの返り値が渡され、エラー理由は「どのPromiseもresolveされなかったよ!」といった趣旨の別のエラーになります。
Promise.allと逆の性質を持っているとも言えますね。
複数のAPIエンドポイントにリクエストし、一番最初にレスポンスしたものを使いたい、そんなときに便利な新メソッドです。

await Promise.any([p1, p2, p3, ...])
// 一番最初に終わったPromiseの返り値

Promise.race

引数のPromiseの実行が1つでも正常に完了するもしくは1つでも失敗するとresolve/rejectされます。
1つのPromiseの結果が決まると、あとのPromiseの結果はすべて無視されます。
返り値には一番最初にresolveされたPromiseの返り値が渡され、エラー理由も同様に一番最初にrejectされたPromsieのものが渡されます。

await Promise.race([p1, p2, p3, ...])
// 一番最初に終わったPromiseの返り値

まとめ

Promise. all allSettled any race
1つでも成功 処理を続ける 処理を続ける その値でresolve その値でresolve
1つでも失敗 その理由でreject 処理を続ける 処理を続ける その理由でreject
すべて成功 すべての値でresolve すべての値でresolve - -
すべて失敗 - すべての値でreject 別のエラーでreject -
すべて確定[1] - すべての値と理由でresolve - -
Promise. all allSettled any race
結果が単数
結果が複数
理由が単数
理由が複数

場面によって適切なメソッドが変わってきます。が、これを制したあなたはPromiseの覇者と言えるでしょう!

脚注
  1. 数を問わず、resolve/rejectがすべて決まったことを示しています。Promise.allSettled特有の処理ですね。 ↩︎