Bitlyst

Promise APIs Compared: all vs race vs any vs allSettled

A practical and conceptual comparison of Promise.all, Promise.race, Promise.any, and Promise.allSettled.

3 min read#javascript#promises#async#event loop

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

APIResolves whenRejects whenTypical use
Promise.allAll promises resolveAny promise rejectsAll-or-nothing
Promise.raceFirst promise settlesFirst promise settlesTimeout / fastest
Promise.anyFirst promise resolvesAll promises rejectFirst success
Promise.allSettledAll promises settle❌ Never rejectsCollect results

🔹 Promise.all

Behavior

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

Timeline

code
A ─────┐
B ─────┼──► resolve
C ─────┘

When to use

✅ You need all results
❌ One failure should stop everything

Common mistake

code
await Promise.all(tasks); // crashes if one fails

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
code
await Promise.race([
  fetch("/data"),
  timeout(3000),
]);

Timeline

code
timeout ──► reject (wins)
fetch    ───────────► ignored

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
code
const result = await Promise.any([
  fetch("/cdn-1"),
  fetch("/cdn-2"),
  fetch("/cdn-3"),
]);

Timeline

code
cdn-1 ✖
cdn-2 ✖
cdn-3 ✔ ──► resolve

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
code
const results = await Promise.allSettled([
  fetch("/a"),
  fetch("/b"),
  fetch("/c"),
]);

Result shape

code
[
  { status: "fulfilled", value: ... },
  { status: "rejected", reason: ... },
]

Timeline

code
A ✔
B ✖
C ✔ ──► resolve with report

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:

code
await a();
await b();

This is concurrent:

code
await Promise.all([a(), b()]);

🧪 Real-World Use Cases

ScenarioBest API
Load page dataPromise.all
Add request timeoutPromise.race
Fallback APIPromise.any
Batch processingPromise.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

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

✅ Summary Table

APIStops earlyRejectsUse for
allMust-have-all
raceFastest / timeout
any✅ (all fail)First success
allSettledFull report

✨ Final Takeaway

Choose the Promise API based on failure behavior, not speed.
They all run concurrently — the difference is when you stop waiting.

You made it to the end!

Did this help? Leave a reaction — it takes one second.

 

Got feedback? 💬

Typo, suggestion, question — I read every message.

Comments

Mohsen Fallahnejad
Mohsen Fallahnejad

Writing bite-sized JS, React & Next.js tips

Get new posts in your inbox

No spam. Unsubscribe any time.