Interview Prep9 min read ยท Updated 2026-03-10

Promise.all vs allSettled vs race vs any: The Complete Comparison

JavaScript has four Promise combinator methods and each handles failure differently. Picking the wrong one means either crashing when partial failure is acceptable, or missing errors when they should abort the operation.

๐Ÿ’ก Practice these concepts interactively with AI feedback

Start Practicing โ†’

All four run multiple Promises concurrently. All four return a single Promise. The difference โ€” the entire decision โ€” is how they handle failures.

The Quick Reference

| Method | Resolves when | Rejects when | Use case | |---|---|---|---| | Promise.all | ALL resolve | ANY rejects | All-or-nothing operations | | Promise.allSettled | ALL settle (either way) | Never | Batch operations with partial failure | | Promise.race | FIRST settles (resolve or reject) | FIRST settles with rejection | Timeouts, first-response wins | | Promise.any | FIRST resolves | ALL reject | Redundant sources, first success wins |

All four start all Promises simultaneously โ€” none waits for one to finish before starting the next. The difference is purely in how the returned Promise resolves.

Promise.all โ€” All or Nothing

Resolves when every Promise resolves. Rejects as soon as any single Promise rejects.

const [users, posts, comments] = await Promise.all([
  fetchUsers(),
  fetchPosts(),
  fetchComments(),
])
// All three run simultaneously
// If any fails, the entire operation fails

The result is an array in input order โ€” regardless of which Promise resolved first:

const results = await Promise.all([
  delay(300).then(() => 'slow'),
  delay(100).then(() => 'fast'),
  delay(200).then(() => 'medium'),
])
// ['slow', 'fast', 'medium'] โ€” always input order, not completion order

On rejection โ€” fail-fast:

try {
  const results = await Promise.all([
    fetchUser(1),    // resolves in 200ms
    fetchUser(2),    // rejects in 100ms
    fetchUser(3),    // resolves in 150ms
  ])
} catch (err) {
  // Runs after 100ms with fetchUser(2)'s rejection
  // fetchUser(1) and fetchUser(3) are still running but their results are ignored
}

Promise.all is the right choice when all results are required for the operation to make sense. Fetching a product page that requires product data, seller data, and reviews โ€” if any one fails, the page can't render and you want to know immediately.

Promise.allSettled โ€” Wait for Everything, Fail Nothing

Resolves when every Promise settles โ€” fulfilled or rejected. Never rejects itself.

const results = await Promise.allSettled([
  fetchUser(1),
  fetchUser(2),  // will reject
  fetchUser(3),
])

results.forEach(result => { if (result.status === 'fulfilled') { console.log('Success:', result.value) } else { console.log('Failed:', result.reason) } })

Each result object has one of two shapes:

Real-world use โ€” dashboard with independent sections:

async function loadDashboard(userId) {
  const [statsResult, activityResult, notificationsResult] = await Promise.allSettled([
    fetchStats(userId),
    fetchActivity(userId),
    fetchNotifications(userId),
  ])

return { stats: statsResult.status === 'fulfilled' ? statsResult.value : null, activity: activityResult.status === 'fulfilled' ? activityResult.value : [], notifications: notificationsResult.status === 'fulfilled' ? notificationsResult.value : [], errors: [statsResult, activityResult, notificationsResult] .filter(r => r.status === 'rejected') .map(r => r.reason), } }

Three independent API calls. If notifications fail, the user still sees stats and activity. The failure is tracked but doesn't abort everything. Use allSettled whenever partial failure is acceptable.

Promise.race โ€” First Across the Line, Win or Lose

Resolves or rejects with the outcome of whichever Promise settles first โ€” whether that's a resolution or a rejection.

const result = await Promise.race([
  fetchData(),
  timeout(5000),   // rejects after 5 seconds
])
// Resolves with fetchData()'s value if it completes in < 5 seconds
// Rejects with timeout error if fetchData() takes > 5 seconds

Implementing a timeout:

function withTimeout(promise, ms) {
  const timer = new Promise((_, reject) =>
    setTimeout(() => reject(new Error(Timed out after ${ms}ms)), ms)
  )
  return Promise.race([promise, timer])
}

try { const data = await withTimeout(fetchSlowAPI(), 3000) } catch (err) { if (err.message.startsWith('Timed out')) { console.error('Request took too long') } }

Finding the fastest server:

const fastest = await Promise.race([
  fetchFromServer('us-east'),
  fetchFromServer('eu-west'),
  fetchFromServer('ap-south'),
])
// Use whichever responds first

The critical nuance: race doesn't cancel the other Promises when one wins. The others keep running โ€” their results are just ignored. If they have side effects, those still happen.

Promise.any โ€” First Success, Ignore Failures

Resolves with the first Promise that fulfills. Rejects only if ALL Promises reject.

const result = await Promise.any([
  fetchFromCDN1(),    // might fail
  fetchFromCDN2(),    // backup
  fetchFromCDN3(),    // secondary backup
])
// Returns as soon as any one CDN responds successfully
// Only fails if ALL three CDNs fail

When all reject, it throws an AggregateError containing all rejection reasons:

try {
  const data = await Promise.any([
    failingOperation1(),
    failingOperation2(),
    failingOperation3(),
  ])
} catch (err) {
  err instanceof AggregateError  // true
  err.errors  // [error1, error2, error3] โ€” all three rejection reasons
}

vs Promise.race: race settles on the first outcome regardless of success or failure. any waits for the first success, skipping failures. If you have redundant sources where any one succeeding is enough, any is the right tool.

// race: if the first one fails, you fail immediately
// any: if the first one fails, try the next, and the next...

const image = await Promise.any([ loadFromCache(), loadFromCDN(), loadFromOrigin(), ]) // Returns the first to succeed โ€” naturally degrades through backups

Comparison: Behavior on Mixed Results

Given: [resolves(A), rejects(E), resolves(B)]

| Method | Result | |---|---| | Promise.all | Rejects with E | | Promise.allSettled | Resolves with [{status:'fulfilled',value:A}, {status:'rejected',reason:E}, {status:'fulfilled',value:B}] | | Promise.race | Resolves or rejects with whichever settled first | | Promise.any | Resolves with A (first fulfillment) |

The Decision Tree

Do all results need to succeed for the operation to work?
  Yes โ†’ Promise.all

Can the operation succeed even if some inputs fail? Yes โ†’ Promise.allSettled

Do you need the first result (success or failure)? Yes โ†’ Promise.race (typically for timeouts)

Do you need the first successful result, ignoring failures? Yes โ†’ Promise.any (redundant sources, fallback chains)

Sequential vs Parallel: The Mistake That Costs Performance

All four combinators run Promises in parallel โ€” they start all operations simultaneously. But there's one common mistake that accidentally makes them sequential:

// โŒ This creates Promises sequentially, then passes them to all:
// fetchUser() starts immediately when called, not when Promise.all runs
const p1 = await fetchUser(1)  // starts AND awaits user 1
const p2 = await fetchUser(2)  // starts AND awaits user 2 (after user 1 finishes)
// Total time: sum of both

// โœ“ Create all Promises first, then combine: const p1 = fetchUser(1) // starts user 1 (no await) const p2 = fetchUser(2) // starts user 2 immediately await Promise.all([p1, p2]) // waits for both // Total time: max of both

// โœ“ Or inline โ€” both start simultaneously: await Promise.all([fetchUser(1), fetchUser(2)])

The key is that calling an async function starts the operation. Awaiting it waits for the result. Pass un-awaited Promises to Promise.all, not awaited values.

๐Ÿ“š Practice These Topics
Event loop
6โ€“10 questions
Promises
7โ€“12 questions
Async await
5โ€“8 questions
Callbacks
3โ€“5 questions

Put This Into Practice

Reading articles is passive. JSPrep Pro makes you actively recall, predict output, and get AI feedback.

Start Free โ†’Browse All Questions

Related Articles

Core Concepts
map() vs forEach() in JavaScript: Which One to Use and Why It Matters
7 min read
Core Concepts
Arrow Functions vs Regular Functions in JavaScript: 6 Key Differences
9 min read
Core Concepts
null vs undefined in JavaScript: What They Mean, When They Appear, and How to Handle Each
7 min read