3秒でわかる
複数の非同期処理を同時に走らせ、全部そろうのを待つメソッド。順番に await するより待ち時間が縮まるので、画面の初期表示で使います。
もう少し詳しく
どういうものか
Promise.all は、Promise の配列を受け取り、すべてが解決したときに結果の配列を返す関数です。渡した順番のまま結果が並ぶので、どれが先に終わったかを気にせず受け取れます。
1つでも失敗すると、その時点で全体が失敗になります。残りの処理が止まるわけではなく、結果が捨てられるだけです。
なぜ必要か
3つの API をそれぞれ200ミリ秒かかる形で順に await すると、合計600ミリ秒待ちます。互いに依存していないなら、同時に投げれば最も遅い1つ分で済みます。画面の初期表示で複数のデータを取りに行く場面では、この差がそのまま体感速度になります。
具体例
// 直列 — 合計で約600ミリ秒
const user = await fetchUser(id);
const posts = await fetchPosts(id);
const stats = await fetchStats(id);
// 並列 — 最も遅いものだけ待つ。約200ミリ秒
const [user2, posts2, stats2] = await Promise.all([
fetchUser(id),
fetchPosts(id),
fetchStats(id),
]);配列の要素数が動く場合は map と組み合わせます。
const ids = [1, 2, 3, 4];
const users = await Promise.all(ids.map((id) => fetchUser(id)));つまずきやすいところ
map に渡すコールバックを async にしたまま await を付け忘れると、Promise の配列がそのまま返り、中身が Promise { の配列になります。Promise.all で包むのを忘れた形です。
依存関係があるものを並列にしてしまう誤りもあります。ログインして得たトークンで次を呼ぶ、という順序が必要な処理は直列のままにします。並列にできるのは互いに独立したものだけです。
失敗の扱いも注意が要ります。100件を Promise.all に渡して1件が失敗すると、成功した99件の結果も受け取れません。全部の結末を知りたいなら Promise.allSettled を使います。
大量に同時実行して相手のサーバーに負荷をかけたり、レート制限に当たったりする事故も定番です。件数が多いときは、10件ずつに区切って順に回すなど、同時実行数を抑えます。
似た用語との違い
| メソッド | 終わる条件 | 戻り値 |
|---|---|---|
| Promise.all | 全部成功、または1つ失敗 | 結果の配列 |
| Promise.allSettled | 全部が決着 | 成否と値を含む配列 |
| Promise.race | 最初に決着した1つ | その1つの結果 |
| Promise.any | 最初に成功した1つ | その1つの値 |