blog

Promise.allとPromise.allSettledの違い

まだまだ勉強中の方もそうでない方も、JS言語は独自のスピードで進化し続けています。瞬く間に、Promiseはそのツールキットの中から選択できる別のメソッドを持ち、それはリジェクトにぶつかるペインポイン...

Sep 1, 2020 · 4 min. read
シェア

あなたがまだ学んでいるかどうかに関わらず、JS言語は独自の急速なペースで進化し続けています。あれよあれよという間に、PromiseのツールキットにはPromise.allを補完するようなPromise.allSettledという別のメソッドが追加され、Promise.allで拒絶されるという痛みにぶつかる問題を軽減してくれます。

Promise.allのペインポイントの解決

ほとんどの場合、Promise.allは次のように複数のPromiseを並行して処理する必要がある場合にうまく機能します。

const delay = n => new Promise(resolve => setTimeout(resolve, n));
const promises = [
 delay(100).then(() => 1),
 delay(200).then(() => 2),
 ]
Promise.all(promises).then(values=>console.log(values))
// 最終出力:[1, 2]

しかし、プロミスの1つが例外をスローしてRETRIEVEDされると、状況は厄介になります。

const promises = [
 delay(100).then(() => 1),
 delay(200).then(() => 2),
 Promise.reject(3)
 ]
Promise.all(promises).then(values=>console.log(values))
// 最終出力: Uncaught 3
Promise.all(promises)
.then(values=>console.log(values))
.catch(err=>console.log(err))
// catch文を追加した後の最終出力: 3

catchで例外をキャッチできるにもかかわらず、正常に実行された他のPromiseからのメッセージが、まるで海に落とされたかのように失われていることに気づくでしょう。

オール・オア・ナッシング、それがPromise.all自体の強い論理であり、ペインポイントの源です。それが間違っているとは言えませんが、Promise.allSettledが足場を固める余地は残されています。

このロジックを処理するためにPromise.allSettledを使ったらどうでしょうか?

const promises = [
 delay(100).then(() => 1),
 delay(200).then(() => 2),
 Promise.reject(3)
 ]
Promise.allSettled(promises).then(values=>console.log(values))
// 最終出力:
// [
// {status: "fulfilled", value: 1},
// {status: "fulfilled", value: 2},
// {status: "rejected", value: 3},
// ]

すべてのプロミスのデータがthen文に含まれ、各プロミスの戻り値には現在のプロミスのステータスを示す追加のステータスフィールドがあり、どのプロミスの情報も失われていないことがわかります。

そのため、Promise.allSettledを使用する場合は、then文に集中するだけで、例外によってプロミスが中断された場合でも、最初からやり直すことなく、成功したプロミスを適切に処理することができます。

Promise.allSettled の現在のマクロサポート

nodejsはPromise.allSettledのサポートを追加しており、主要なブラウザは2019年のリリースでそれぞれこのメソッドをサポートしています。

この方法をサポートしていない環境では、この方法を実装したオープンソースコミュニティのnpmパッケージを直接参照することができます:

あるいは、Promise.allをベースにしたpolyfillを書いて、プロジェクトにパッチを当てることもできます:

if (Promise && !Promise.allSettled) {
 Promise.allSettled = function (promises) {
 return Promise.all(promises.map(function (promise) {
 return promise.then(function (value) {
 return { state: 'fulfilled', value: value };
 }).catch(function (reason) {
 return { state: 'rejected', reason: reason };
 });
 }));
 };
}

結論

Promise.allSettledはPromise.allを補完するもので,複数のプロミスが並列に存在する場合,rejectが出現すると他のプロミスのデータが失われるという問題に対処するための追加手段を提供します.

Read next

uniappページから外部のvueプロジェクトにジャンプするには?

最後にユーザー情報だけ必要なので、jsメソッドで横取りしています。 このメソッドで直接取得すると、createdの中から呼び出さないといけないので、vueでは分割が未定義というエラーが出ます。 しかし、createdで初期化すると、非同期読み込みになり、データがまだないので、配列やオブジェクトを操作しても値がありません。

Sep 1, 2020 · 2 min read