DEV Community

Mohsen Fallahnejad
Mohsen Fallahnejad

Posted on Edited on Originally published at bitlyst.blog

Promise APIs Compared: all vs race vs any vs allSettled

Promise APIs Comparison: all vs race vs any vs allSettled

JavaScript provides multiple Promise combinators.

They all start promises concurrently, but they differ in when they resolve/reject and what they return.

Understanding the differences prevents subtle bugs and improves performance.


🧠 Quick Overview

API Resolves when Rejects when Typical use
Promise.all All promises resolve Any promise rejects All-or-nothing
Promise.race First promise settles First promise settles Timeout / fastest
Promise.any First promise resolves All promises reject First success
Promise.allSettled All promises settle ❌ Never rejects Collect results

πŸ”Ή Promise.all

Behavior

  • Waits for all promises to resolve
  • Rejects immediately if any promise rejects
await Promise.all([
  fetch("/a"),
  fetch("/b"),
  fetch("/c"),
]);
Enter fullscreen mode Exit fullscreen mode

Timeline

A ─────┐
B ─────┼──► resolve
C β”€β”€β”€β”€β”€β”˜
Enter fullscreen mode Exit fullscreen mode

When to use

βœ… You need all results

❌ One failure should stop everything

Common mistake

await Promise.all(tasks); // crashes if one fails
Enter fullscreen mode Exit fullscreen mode

If partial success is acceptable β†’ use allSettled.


πŸ”Ή Promise.race

Behavior

  • Settles as soon as the first promise settles
  • That settlement can be resolve or reject
await Promise.race([
  fetch("/data"),
  timeout(3000),
]);
Enter fullscreen mode Exit fullscreen mode

Timeline

timeout ──► reject (wins)
fetch    ───────────► ignored
Enter fullscreen mode Exit fullscreen mode

When to use

βœ… Timeouts

βœ… First response wins

❌ Not for β€œfirst success only”


πŸ”Ή Promise.any

Behavior

  • Resolves on the first fulfilled promise
  • Rejects only if all promises reject
  • Rejection reason is an AggregateError
const result = await Promise.any([
  fetch("/cdn-1"),
  fetch("/cdn-2"),
  fetch("/cdn-3"),
]);
Enter fullscreen mode Exit fullscreen mode

Timeline

cdn-1 βœ–
cdn-2 βœ–
cdn-3 βœ” ──► resolve
Enter fullscreen mode Exit fullscreen mode

When to use

βœ… Redundant endpoints

βœ… Fallback strategies

❌ When failures matter


πŸ”Ή Promise.allSettled

Behavior

  • Waits for all promises to settle
  • Never rejects
  • Returns status for each promise
const results = await Promise.allSettled([
  fetch("/a"),
  fetch("/b"),
  fetch("/c"),
]);
Enter fullscreen mode Exit fullscreen mode

Result shape

[
  { status: "fulfilled", value: ... },
  { status: "rejected", reason: ... },
]
Enter fullscreen mode Exit fullscreen mode

Timeline

A βœ”
B βœ–
C βœ” ──► resolve with report
Enter fullscreen mode Exit fullscreen mode

When to use

βœ… Logging

βœ… Batch operations

βœ… Partial success allowed


🧠 Mental Model

Think of them as rules for waiting:

  • all β†’ everyone must succeed
  • race β†’ whoever finishes first decides
  • any β†’ first success wins
  • allSettled β†’ everyone reports back

⚠️ Important Notes

  • All promises start immediately
  • None of these APIs make JS parallel
  • They only coordinate async results

This is still sequential:

await a();
await b();
Enter fullscreen mode Exit fullscreen mode

This is concurrent:

await Promise.all([a(), b()]);
Enter fullscreen mode Exit fullscreen mode

πŸ§ͺ Real-World Use Cases

Scenario Best API
Load page data Promise.all
Add request timeout Promise.race
Fallback API Promise.any
Batch processing Promise.allSettled

❌ Common Pitfalls

1. Using all when failures are acceptable

β†’ causes unnecessary crashes

2. Using race for β€œfirst success”

β†’ rejects too early

3. Forgetting AggregateError in any

try {
  await Promise.any(promises);
} catch (e) {
  console.log(e.errors); // list of failures
}
Enter fullscreen mode Exit fullscreen mode

βœ… Summary Table

API Stops early Rejects Use for
all ❌ βœ… Must-have-all
race βœ… βœ… Fastest / timeout
any βœ… βœ… (all fail) First success
allSettled ❌ ❌ Full report

✨ Final Takeaway

Choose the Promise API based on failure behavior, not speed.

They all run concurrently β€” the difference is when you stop waiting.


Originally published on Bitlyst.

Top comments (0)