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"),
]);
Timeline
A ββββββ
B ββββββΌβββΊ resolve
C ββββββ
When to use
β
You need all results
β One failure should stop everything
Common mistake
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
await Promise.race([
fetch("/data"),
timeout(3000),
]);
Timeline
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
const result = await Promise.any([
fetch("/cdn-1"),
fetch("/cdn-2"),
fetch("/cdn-3"),
]);
Timeline
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
const results = await Promise.allSettled([
fetch("/a"),
fetch("/b"),
fetch("/c"),
]);
Result shape
[
{ status: "fulfilled", value: ... },
{ status: "rejected", reason: ... },
]
Timeline
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:
await a();
await b();
This is concurrent:
await Promise.all([a(), b()]);
π§ͺ 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
}
β 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)