Promise.allSettled vs Promise.all:部分的な失敗を適切に処理する

問題

ダッシュボードで複数のAPIを同時に呼び出す必要がありました。Promise.allを使ったところ、1つでも失敗すると全体がrejectされ、成功したデータまで失われてしまいました。

// 1つでも失敗すると全部失われる
try {
  const [users, orders, stats] = await Promise.all([
    fetchUsers(),
    fetchOrders(),   // これが失敗すると
    fetchStats(),
  ]);
} catch (err) {
  // users, statsの結果も使えない
}

解決方法

Promise.allSettledを使えば、すべてのPromiseが完了するまで待ち、それぞれの成功・失敗を個別に確認できます。

const results = await Promise.allSettled([
  fetchUsers(),
  fetchOrders(),
  fetchStats(),
]);

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

実務では以下のようなパターンで使います:

const [usersResult, ordersResult, statsResult] = await Promise.allSettled([
  fetchUsers(),
  fetchOrders(),
  fetchStats(),
]);

const dashboard = {
  users: usersResult.status === 'fulfilled' ? usersResult.value : [],
  orders: ordersResult.status === 'fulfilled' ? ordersResult.value : [],
  stats: statsResult.status === 'fulfilled' ? statsResult.value : null,
};

// 失敗したものだけログ出力
const failures = [usersResult, ordersResult, statsResult]
  .filter(r => r.status === 'rejected');

if (failures.length > 0) {
  console.error('一部のAPIが失敗:', failures.map(f => f.reason));
}

ポイント

  • Promise.allは1つでも失敗すると即座にreject — すべて成功が必須の場合に使います
  • Promise.allSettledはすべて完了後に個別の結果を返します — 部分的な失敗を許容する場合に使います
  • ダッシュボードやバッチ処理など「成功した分は表示し、失敗した分は別途処理」するシナリオに最適です