DESIGN / CODE / INFRA / AI

解説

Promise.allで一つ失敗したら全部止まる?allSettledと結果を比べよう

失敗したときの結果と、ほかの処理の実行を分ける作例。Promise.all・allSettledの順番、完了件数、キャンセルとの違いを確認。

Promise.allで一つ失敗したら全部止まる?allSettledと結果を比べよう
保存リストを見る →
この記事の道しるべ 5項目

複数の非同期処理をPromise.allで待っていたら、一つが失敗した。これで残りも中止されたのかな。Promise.allが拒否されることと、元の処理が中止されることは別だよ。

今回は通信をせず、短いタイマーで架空の三つの仕事を作る。Promiseの基本を知っている人向けに、結果が決まった時点と、全処理が終わった時点を比較しよう。

allは、一つが拒否されると拒否になる

Promise.allは、すべてが成功すれば結果を配列へまとめ、一つでも拒否されると拒否される。成功時の配列は、完了した順ではなく渡した順に対応するよ。

ただし、すでに開始した通信やタイマーを、allが自動的に取り消すわけではない。必要なら、対象の処理が対応する中止方法を別に設計する必要がある。

allSettledは、すべての成否を待つ

allSettledは、それぞれが成功または拒否のどちらかへ決まるまで待ち、statusとvalueまたはreasonを持つ結果の配列を返す。

こちらも配列の順番は入力に対応する。一番先に終わった処理が、必ず配列の先頭へ来るわけではないよ。

小さな例で、完了が続くことを見る

const completed = [];
function task(name, ms, fail = false) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      completed.push(name);
      if (fail) reject(new Error(name));
      else resolve(name);
    }, ms);
  });
}
const jobs = [task("A", 30), task("B", 10, true), task("C", 50)];
try {
  await Promise.all(jobs);
} catch {
  console.log("all: rejected");
}
const results = await Promise.allSettled(jobs);
console.log(results.map(result => result.status));
console.log(completed.length);

この例ではall: rejectedのあと、fulfilled・rejected・fulfilledの三つの状態、完了件数3が出る。Bの失敗があっても、AとCのタイマーは実行されているんだ。

taskを呼んだ時点でタイマーを開始していることにも注目しよう。Promise.allへ関数を並べれば、関数自体を自動で呼んでくれるという例ではないよ。

作例では、結果時点と最終件数を分ける

  1. allを選び実行する。途中で拒否の結果が出ても、最後には三件とも完了することを見る。
  2. allSettledへ変え、三件の状態が入力順でそろうことを確認する。
  3. 完了ログの順番と、結果の配列の順番を比べる。
  4. 「最初から試す」で表示を初期化する。

作例のリセットは、この練習の表示を戻すもの。実際のサーバー処理を取り消したり、通信の失敗を元へ戻したりする仕組みではないよ。

一つでも失敗なら全体を失敗にするか

すべてそろわないと使えない結果なのか、成功した分だけでも扱いたいのかで、合う待ち方が変わる。allSettledにすれば、失敗が自動的に解決するわけでもない。

編集部ではNode.jsとChromiumで、三件の最終完了、状態の順番、途中の結果とリセットを確認した。実ネットワークや業務のキャンセル機構を試した結果ではないよ。イベントの一回限りの登録はonce、返り値の違いはmapとforEachも参考になるね。

動かしてみよう:拒否の結果と残りの処理

二つの待ち方を実行し、結果時点・最終件数・完了ログを比べよう。通信はしないよ。

参考・出典

公開と変更の記録
  • :初回公開

日時は日本時間です。記載のある変更は、確認できた編集記録に基づきます。更新日の違いだけから変更内容を推測して載せることはありません。

更新・訂正の方針 →

みんなのコメント 0

感想や、試してみたことを聞かせてね。コメント・返信は承認後に公開されます。

最初のコメントをどうぞ。