JavaScript 逆引き集 | Promise.allSettled(結果全取得)

JavaScript JavaScript
スポンサーリンク

Promise.allSettled(結果全取得)の基本と実践

Promise.allSettled は「複数の非同期処理が、成功か失敗かに関係なくすべて終わるまで待って、各結果のステータスと値(または理由)をまとめて返す」ためのメソッドです。部分成功を扱いたい場面に向いています。


基本の書き方と返り値

const p1 = Promise.resolve(1);
const p2 = Promise.reject(new Error("oops"));
const p3 = new Promise(res => setTimeout(() => res(3), 100));

const results = await Promise.allSettled([p1, p2, p3]);
console.log(results);
/*
[
  { status: "fulfilled", value: 1 },
  { status: "rejected", reason: Error("oops") },
  { status: "fulfilled", value: 3 }
]
*/
JavaScript
  • 全件完了を待つ: 成否に関わらず「全部終わってから」配列で返す。
  • 結果形式: それぞれが { status: "fulfilled", value } または { status: "rejected", reason }
  • 順序: 入力配列の順序を維持。

直列 vs 並列の使い分け(イメージ)

  • Promise.allSettled: 全ての完了を待ち、成功・失敗の内訳を確認して次の処理へ。
  • Promise.all: 一つでも失敗したら即例外。全部成功前提で扱うとき向き。
  • Promise.race/any: 最初に決着した一件(raceは成功/失敗どちらでも、anyは成功に限る)。

「部分成功を拾って続行したい」「失敗も記録してレポートしたい」なら allSettled が適任です。


すぐ使えるテンプレート集

1) 成功だけ抽出して使う

const settled = await Promise.allSettled([p1, p2, p3]);
const values = settled
  .filter(r => r.status === "fulfilled")
  .map(r => r.value);
console.log(values); // 成功した値だけ
JavaScript

2) 失敗の理由をログにまとめる

const settled = await Promise.allSettled(tasks);
const errors = settled
  .filter(r => r.status === "rejected")
  .map(r => r.reason);
errors.forEach(e => console.error("失敗:", e));
JavaScript

3) API群の部分成功を許容してUIを更新

async function loadDashboard() {
  const [cfg, profile, stats] = await Promise.allSettled([
    fetch("/config").then(r => r.json()),
    fetch("/profile").then(r => r.json()),
    fetch("/stats").then(r => r.json()),
  ]);

  const data = {
    config: cfg.status === "fulfilled" ? cfg.value : null,
    profile: profile.status === "fulfilled" ? profile.value : null,
    stats: stats.status === "fulfilled" ? stats.value : null,
  };
  const errors = [cfg, profile, stats]
    .filter(x => x.status === "rejected")
    .map(x => x.reason);

  // 部分的に表示、失敗は通知
  render(data);
  if (errors.length) notify(errors.map(e => e.message).join("\n"));
}
JavaScript

4) 失敗を握りつぶして継続(デフォルト値採用)

const settled = await Promise.allSettled([
  fetchJSON("/a"),
  fetchJSON("/b"),
  fetchJSON("/c"),
]);

const safe = settled.map(r =>
  r.status === "fulfilled" ? r.value : { ok: false, data: null }
);
JavaScript

実務でのパターンとコツ

  • 部分成功の集約: 一括ロードで一部失敗しても、取得できたものだけで画面を組み立てる。
  • ログ・監視: 失敗理由をまとめてレポート、再試行の対象選定に使う。
  • 非クリティカルの併走: メイン処理と関係しない補助タスク(統計送信、プレフェッチなど)を同時実行し、完了後に状態を集約。
  • 後続処理の分岐: 成功値だけで次の段階へ、失敗はキューに入れてリトライ。
// リトライ対象を抽出して再実行
async function retryRejected(funcs, max = 2) {
  let settled = await Promise.allSettled(funcs.map(f => f()));
  for (let i = 0; i < max; i++) {
    const indices = settled
      .map((r, idx) => ({ r, idx }))
      .filter(x => x.r.status === "rejected")
      .map(x => x.idx);
    if (!indices.length) break;

    const retried = await Promise.allSettled(indices.map(j => funcs[j]()));
    indices.forEach((j, k) => (settled[j] = retried[k]));
  }
  return settled;
}
JavaScript

よくある落とし穴と対策

  • 「成功だけ返る」と誤認: allSettled は成功・失敗を混在で返す。必要に応じてフィルタして使う。
  • エラーを見落とす: 例外としては投げられないため、失敗の確認を自分で行う必要がある。
    • 対策: status === "rejected" の分岐を必ず設け、監視・通知・再試行へつなげる。
  • 大量並列の負荷: 失敗も含めて全件待つため、並列が多いと負担が大きい。
    • 対策: バッチ化や同時数制限(並列キュー)を導入。
  • 順序の勘違い: 返り値配列の順序は入力順。完了速度では並ばない。
    • 対策: インデックスに意味を持たせ、順序前提の処理を書いておく。

練習問題(手を動かして覚える)

// 1) 成否混在の結果を確認
const out = await Promise.allSettled([
  Promise.resolve("A"),
  Promise.reject(new Error("X")),
  new Promise(res => setTimeout(() => res("B"), 50)),
]);
console.log(out);

// 2) 成功だけ抽出して合計
const nums = await Promise.allSettled([
  Promise.resolve(10),
  Promise.reject(new Error("bad")),
  Promise.resolve(5),
]);
const sum = nums
  .filter(r => r.status === "fulfilled")
  .reduce((acc, r) => acc + r.value, 0);
console.log(sum); // 15

// 3) 失敗の理由を一覧表示
const rs = await Promise.allSettled([
  Promise.reject(new Error("network")),
  Promise.resolve("ok"),
  Promise.reject(new Error("timeout")),
]);
rs.filter(r => r.status === "rejected")
  .forEach(r => console.log(r.reason.message));

// 4) デフォルト値で埋める
const filled = rs.map(r => r.status === "fulfilled" ? r.value : "N/A");
console.log(filled);
JavaScript

直感的な指針

  • 「全部終わってから、成功・失敗ごとに結果を確認したい」なら allSettled。
  • 成功だけ使う・失敗はログやリトライへ—といった分岐を前提に設計。
  • 大量並列は負荷に注意。必要なら同時数を絞る。
  • 返り値の順序は入力どおり。インデックス前提で扱う。
タイトルとURLをコピーしました