JavaScript | 非同期処理:Promise 応用 – Promise.allSettled

JavaScript JavaScript
スポンサーリンク

Promise.allSettled を一言でいうと

Promise.allSettled は、
「複数の Promise が “成功しても失敗しても、とにかく全部終わるまで待ち、結果をぜんぶレポートしてくれる関数」 です。

Promise.all は「1つでも失敗したら全体エラー」でしたが、
Promise.allSettled「失敗しても止めない。全員が終わるまで待つ」 というスタンスです。

ここが重要です。
「全部成功してほしいとき」は Promise.all
「成功・失敗に関わらず、全員の結果を知りたいとき」は Promise.allSettled

と覚えると整理しやすいです。


基本の形と返ってくる結果の構造

どう呼ぶか(シグネチャ)

形は Promise.all と似ています。

Promise.allSettled([promise1, promise2, promise3])
  .then((results) => {
    // ここで results を見る
  });
JavaScript

違いは「results」の中身です。
Promise.all の場合は「成功した値だけ」の配列でしたが、
allSettled の場合は、各 Promise ごとに「状態+値 or 理由」が入ったオブジェクトの配列 になります。

それぞれの要素は、ざっくりいうとこのどちらかです。

成功した場合:

{
  status: "fulfilled",
  value: (成功した値)
}
JavaScript

失敗した場合:

{
  status: "rejected",
  reason: (エラーオブジェクトなど)
}
JavaScript

簡単なサンプルで全体像を見る

const p1 = Promise.resolve(1);
const p2 = Promise.reject(new Error("失敗しました"));
const p3 = Promise.resolve(3);

Promise.allSettled([p1, p2, p3]).then((results) => {
  console.log(results);
});
JavaScript

results の中身はこんなイメージになります。

[
  { status: "fulfilled", value: 1 },
  { status: "rejected",  reason: Error("失敗しました") },
  { status: "fulfilled", value: 3 }
]
JavaScript

ここが重要です。
Promise.allSettled は「成功だけ」ではなく、「成功か失敗か+その中身」をすべて教えてくれる
ので、「誰がどうなったか」を自分で判断できます。


Promise.all との違いを感覚でつかむ

Promise.all は「1つでも落ちたら全体エラー」

まずは Promise.all 側を思い出します。

const ok1 = Promise.resolve("OK1");
const fail = Promise.reject(new Error("NG"));
const ok2 = Promise.resolve("OK2");

Promise.all([ok1, fail, ok2])
  .then((values) => {
    console.log("成功:", values);
  })
  .catch((err) => {
    console.error("エラー:", err.message);
  });
JavaScript

この場合、

fail が失敗した時点で全体が reject(失敗)扱いになり、
then は呼ばれず、catch に飛びます。
ok2 やその値は、結果として使われません。

Promise.allSettled は「みんなの結果を最後まで見る」

同じ配列を allSettled に渡すとどうなるか。

Promise.allSettled([ok1, fail, ok2])
  .then((results) => {
    console.log(results);
  });
JavaScript

先ほどと同じように、

ok1 → success
fail → error
ok2 → success

という順番で終わりますが、
allSettled「全員が終わるまで待ち、その上で結果の一覧を返す」 ので、
3 つとも必ず results に含まれます。

ここが重要です。
Promise.all:全部成功してほしいとき。「1つでもエラーなら全体エラーでいい」ケース。
Promise.allSettled:一人でもエラーがいるかもしれないけど、「とにかく全員の結果が知りたい」ケース。


実用的な例:成功分だけ使って、失敗は失敗で把握する

やりたいことのイメージ

例えばこんな場面を考えます。

3 つの API からデータを取る
ただし、1つくらい失敗しても、取れたデータだけで画面を作りたい
同時に「どれが失敗したか」もログしておきたい

こういうとき、Promise.all だと「1つ落ちたら全部エラー」となるので都合が悪いです。
allSettled なら「取れた分だけ使う+失敗も把握する」がやりやすくなります。

擬似 API を allSettled でまとめて処理する

まず、適当な擬似 API を用意します。

function fetchUser() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({ id: 1, name: "Taro" });
    }, 500);
  });
}

function fetchPosts() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject(new Error("投稿取得に失敗"));
    }, 800);
  });
}

function fetchNotifications() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(["通知A", "通知B"]);
    }, 300);
  });
}
JavaScript

これを Promise.allSettled で実行します。

Promise.allSettled([
  fetchUser(),
  fetchPosts(),
  fetchNotifications(),
]).then((results) => {
  const [userResult, postsResult, notificationsResult] = results;

  if (userResult.status === "fulfilled") {
    console.log("ユーザー:", userResult.value);
  } else {
    console.error("ユーザー取得失敗:", userResult.reason);
  }

  if (postsResult.status === "fulfilled") {
    console.log("投稿:", postsResult.value);
  } else {
    console.error("投稿取得失敗:", postsResult.reason);
  }

  if (notificationsResult.status === "fulfilled") {
    console.log("通知:", notificationsResult.value);
  } else {
    console.error("通知取得失敗:", notificationsResult.reason);
  }
});
JavaScript

ここでのポイントは、

それぞれの結果に対して status を見て、
成功だったら value、失敗だったら reason を見る

というふうに、「成功/失敗を自分で判定して処理を分けられる」ことです。

ここが重要です。
Promise.allSettled は「どれか一つ失敗したら終わり」ではなく、
「全件の成功/失敗レポートが欲しい」場面のための道具
です。


戻り値の配列の中身をもう少し丁寧に理解する

fulfilled の要素

成功した Promise の結果オブジェクトはこうなります。

{
  status: "fulfilled",
  value: 成功時の値
}
JavaScript

例えば:

Promise.allSettled([
  Promise.resolve(10),
]).then(([result]) => {
  console.log(result);
  // { status: "fulfilled", value: 10 }
});
JavaScript

rejected の要素

失敗した Promise の結果オブジェクトはこうです。

{
  status: "rejected",
  reason: 失敗時のエラー(Error オブジェクトなど)
}
JavaScript

例:

Promise.allSettled([
  Promise.reject(new Error("エラーです")),
]).then(([result]) => {
  console.log(result);
  // { status: "rejected", reason: Error("エラーです") }
});
JavaScript

大事なのは、

成功なら value プロパティを読む
失敗なら reason プロパティを読む

という、「見るべき場所」が違うことです。

ここが重要です。
allSettled の結果は「成功と失敗で形が微妙に違うオブジェクトの配列」。
なので、まずは status を見て、「どっち側か」を判定してから中身を触るのが鉄則です。


情報を整理して「成功分だけ」取り出すテクニック

filter と map を使う

「成功したものだけ欲しい」「失敗したものだけログしたい」といったケースが多いので、
配列操作と組み合わせるパターンも紹介します。

Promise.allSettled([fetchUser(), fetchPosts(), fetchNotifications()])
  .then((results) => {
    const fulfilled = results.filter((r) => r.status === "fulfilled");
    const rejected  = results.filter((r) => r.status === "rejected");

    console.log("成功したもの:", fulfilled);
    console.log("失敗したもの:", rejected);
  });
JavaScript

さらに、成功した値だけ取り出したいなら:

const values = fulfilled.map((r) => r.value);
console.log("成功値の一覧:", values);
JavaScript

こうすると、

どれが成功したか
どれが失敗したか
成功したものの値だけの配列

といった情報が簡単に取り出せます。


初心者としての「Promise.allSettled」の押さえどころ

最後に、本当に大事なポイントだけを整理します。

Promise.allSettled([p1, p2, p3]) は、「p1, p2, p3 が成功でも失敗でもとにかく全部終わるまで待ち、その結果を配列で返す」関数。

結果の配列の各要素は { status: "fulfilled", value: ... } または { status: "rejected", reason: ... } のどちらか。
まず status を見てから value or reason を見る。

Promise.all は「1つでも失敗したら全体エラー」で途中終了するが、
Promise.allSettled は「誰かが失敗しても全員の結果が出揃うまで終了しない」。

「全部成功しなくても、成功した分だけ使いたい」「どれが失敗したかも把握したい」ときに、allSettled がとても役に立つ。

ここが重要です。
Promise.all は “オール合格前提のテスト”、
Promise.allSettled は “全員分の採点結果を知りたいテスト”

というイメージを持っておくと、使い分けが感覚的に分かりやすくなります。

練習としては、

resolve する Promise と reject する Promise をいくつか作って
Promise.allSettled に渡し、status / value / reason を console.log で確認してみる

これを一度やってみると、
「成功・失敗が混ざっていても、落ち着いて結果を整理できる感覚」がかなりしっかり身につきます。

タイトルとURLをコピーしました