2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Promise.all/allSettled/race/anyの使い分け4選

2
Posted at

複数の非同期処理をまとめて扱うとき、Promise.allしか使ったことがない、という方もいるのではないでしょうか。実はPromiseにはall以外にもallSettled・race・anyという仲間がいて、それぞれ「複数の結果をどう扱うか」の方針が違います。今回は4つを実際に動かして、挙動の違いを確認しました。

検証コード

3つの疑似非同期処理(成功・失敗・タイミングが異なる)を用意して、4つのメソッドに通します。

const mk = (val, ms, fail) =>
  new Promise((res, rej) => setTimeout(() => (fail ? rej(val) : res(val)), ms));

const p1 = mk('p1 success', 30, false); // 30msで成功
const p2 = mk('p2 failed', 10, true);   // 10msで失敗
const p3 = mk('p3 success', 50, false); // 50msで成功

1. Promise.all — 1つでも失敗したら、即座に失敗扱い

try {
  const r = await Promise.all([p1, p2, p3]);
  console.log(r);
} catch (e) {
  console.log('caught:', e);
}
// → caught: p2 failed

p2が失敗した時点で、p1やp3がまだ実行中でもPromise.all全体が失敗(reject)として扱われます。全部が成功して初めて意味がある処理(例: 複数のAPIから必要なデータを全部揃えたい場合)に向いています。裏を返すと、1つの失敗が全体を巻き込むという性質があります。

2. Promise.allSettled — 成功・失敗を問わず、全部の結果を待つ

const r = await Promise.allSettled([p1, p2, p3]);
console.log(r);
// → [
//     { status: 'fulfilled', value: 'p1 success' },
//     { status: 'rejected', reason: 'p2 failed' },
//     { status: 'fulfilled', value: 'p3 success' }
//   ]

allSettledは失敗があっても途中で打ち切らず、全員の結果(成功したか失敗したか)をオブジェクトの配列として返します。「一部が失敗してもいいから、成否をまとめて把握したい」場面に向いています。複数の通知を送る処理で、送れたものと送れなかったものを両方記録したい、というようなケースが典型です。

3. Promise.race — 最初に決着したものを採用(成功でも失敗でも)

try {
  const r = await Promise.race([p2 /* 10msで失敗 */, p3 /* 50msで成功 */]);
} catch (e) {
  console.log('caught:', e);
}
// → caught: p2 failed(先に決着したp2の失敗が採用される)

raceは「一番最初にresolve・rejectされたもの」をそのまま採用します。成功か失敗かは問わず、最初に決着したものが勝ちです。タイムアウト処理の実装(本来の処理と、一定時間で失敗するタイマーをraceさせる)でよく使われます。

4. Promise.any — 最初に成功したものを採用(全部失敗したときだけ失敗)

const r = await Promise.any([p2 /* 失敗 */, p1 /* 成功 */]);
console.log(r); // → 成功した方の値

try {
  await Promise.any([失敗するPromiseたち]);
} catch (e) {
  console.log(e.name, e.errors); // → AggregateError [...]
}

anyはraceに似ていますが、失敗は無視して、最初に成功したものだけを採用します。全部が失敗した場合にだけ、まとめてAggregateErrorという特別なエラー(errorsプロパティに全部の失敗理由が配列で入っている)を投げます。複数のミラーサーバーのうち、どれか1つから応答があればいい、という場面に向いています。

使い分けの早見表

メソッド 成功の条件 失敗の扱い
Promise.all 全部成功 1つでも失敗したら即失敗
Promise.allSettled (常に成功として結果を返す) 失敗も結果の一部として記録される
Promise.race 最初に決着(成功/失敗問わず) 最初が失敗なら失敗が採用される
Promise.any 最初に成功したもの 全部失敗して初めて失敗

まとめ

  • all: 全部そろって初めて意味がある処理に。1つの失敗で全体が失敗する
  • allSettled: 一部の失敗を許容しつつ、全員の結果を把握したいときに
  • race: 最初に決着したものを使う。タイムアウト実装の定番
  • any: 最初の成功だけがほしいときに。全滅したときだけAggregateError

「複数のPromiseをどう待つか」を書くたびにallしか使っていなかった方は、場面に応じて他の3つも検討してみてください。


未経験者向けの講座を運営しています

未経験から Next.js + Supabase + Claude Code で Webアプリを公開するまで を、全24セッションで体系化した教材です。Claude Code を学習パートナーにする CLAUDE.md と学習モード(learner / developer)の設計までセットで含みます。

※ Qiita読者の方には易しすぎる内容なので、初心者の知り合いへの紹介や社内研修の参考としてどうぞ。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?