Promise.allSettled vs Promise.all: Handle Partial Failures Gracefully

Problem

Building a dashboard that calls multiple APIs concurrently. Using Promise.all, a single API failure rejects everything — even the successful responses are lost.

// One failure kills all results
try {
  const [users, orders, stats] = await Promise.all([
    fetchUsers(),
    fetchOrders(),   // If this fails...
    fetchStats(),
  ]);
} catch (err) {
  // Can't access users or stats either
}

Solution

Promise.allSettled waits for all promises to complete and reports each result individually.

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

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

A practical pattern for production:

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,
};

// Log only the failures
const failures = [usersResult, ordersResult, statsResult]
  .filter(r => r.status === 'rejected');

if (failures.length > 0) {
  console.error('Some APIs failed:', failures.map(f => f.reason));
}

Key Points

  • Promise.all rejects immediately on the first failure — use when all promises must succeed
  • Promise.allSettled waits for all to complete and gives individual results — use when partial failure is acceptable
  • Ideal for dashboards, batch operations, or any scenario where you want to show what succeeded and handle failures separately