JavaScript Promise の並列処理:all・allSettled・race の使い方

スポンサーリンク

JavaScript Promise の並列処理:all・allSettled・race の使い方

複数の非同期処理を並列で実行するには Promise.allPromise.allSettledPromise.racePromise.any を使います。


早わかりまとめ

メソッド 解決タイミング 失敗時の挙動
Promise.all 全件成功したとき 1件でも失敗したら即 reject
Promise.allSettled 全件完了したとき 失敗してもすべての結果を収集
Promise.race 最初の1件が完了したとき 失敗でも成功でも最初の結果を返す
Promise.any 最初の成功が出たとき 全件失敗したとき reject

Promise.all:全件成功が前提のとき

const fetchUser = () => fetch('/api/user').then((r) => r.json())
const fetchPosts = () => fetch('/api/posts').then((r) => r.json())

const [user, posts] = await Promise.all([fetchUser(), fetchPosts()])
console.log(user, posts)

1件でも失敗(reject)すると全体が reject になります。「全部成功しないと意味がない」ケースに使います。

try {
  const results = await Promise.all([
    fetchUser(),
    fetchPosts(),
    fetchComments(),
  ])
} catch (e) {
  // どれか1件が失敗したら catch に来る
  console.error(e)
}

Promise.allSettled:失敗してもすべての結果を収集したいとき

const results = await Promise.allSettled([
  fetch('/api/user').then((r) => r.json()),
  fetch('/api/broken-endpoint').then((r) => r.json()),
  fetch('/api/posts').then((r) => r.json()),
])

results.forEach((result) => {
  if (result.status === 'fulfilled') {
    console.log('成功:', result.value)
  } else {
    console.error('失敗:', result.reason)
  }
})

各要素が { status: 'fulfilled', value } または { status: 'rejected', reason } の形になります。失敗があっても処理を止めずに全件収集したいときに使います。


Promise.race:最初に完了したものを使うとき

const timeout = (ms) =>
  new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), ms))

try {
  const result = await Promise.race([
    fetch('/api/data').then((r) => r.json()),
    timeout(3000),
  ])
  console.log(result)
} catch (e) {
  console.error('タイムアウトまたはエラー:', e.message)
}

タイムアウト処理の実装でよく使います。成功・失敗どちらでも、最初に完了した Promise の結果を返します。


Promise.any:最初の成功を使うとき

// 複数のミラーからどれか1つ取れれば良いケース
const result = await Promise.any([
  fetch('https://mirror1.example.com/data'),
  fetch('https://mirror2.example.com/data'),
  fetch('https://mirror3.example.com/data'),
])

Promise.race との違い:Promise.any は失敗を無視して最初の成功を待ちます。全件失敗したときだけ AggregateError で reject されます。


直列処理との比較

// ❌ 直列(合計時間 = A + B + C)
const a = await fetchA()
const b = await fetchB()
const c = await fetchC()

// ✅ 並列(合計時間 ≈ max(A, B, C))
const [a, b, c] = await Promise.all([fetchA(), fetchB(), fetchC()])

互いに依存しない処理は Promise.all で並列化するとパフォーマンスが向上します。


まとめ

したいこと 使うもの
全件成功したら結果を使う Promise.all
失敗があっても全件の結果を収集する Promise.allSettled
最初に完了した結果を使う(タイムアウトなど) Promise.race
最初に成功した結果を使う Promise.any
順番に依存する処理を直列で実行する await を直列に書く