複数の非同期処理をまとめて扱うとき、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)の設計までセットで含みます。
- ▶ ライブデモ(インストール不要・無料で今すぐ見られます)→ https://trial-web-ayies128s-projects.vercel.app/?ref=qiita
- 教材完全版+月5,500円のメンタリング(全24セッション+チャット質問し放題)→ https://menta.work/plan/20251?ref=qiita
- 無料体験版(git clone して自分の手元で動かす・最初の数セッション分・⭐ Star もよろしくお願いします)→ https://github.com/ayies128/next-ai-camp-trial
- YouTube『AIエンジニア情報局』(AI×開発ニュースを1本5分でキャッチアップできる別運営チャンネル・無料)→ https://www.youtube.com/channel/UC1rXVD9WYsQPQEWZyd-A1KA/?ref=qiita
※ Qiita読者の方には易しすぎる内容なので、初心者の知り合いへの紹介や社内研修の参考としてどうぞ。