Beyond Promise.all, JavaScript offers three more combinators that solve specific concurrency problems.
Promise.all — All or Nothing
// Rejects immediately if ANY promise rejects
const results = await Promise.all([
fetch("/api/users"),
fetch("/api/posts"),
fetch("/api/comments")
]);
// If /api/posts fails, you get NOTHINGPromise.allSettled — Get Everything
const results = await Promise.allSettled([
fetch("/api/users"),
fetch("/api/posts"), // Even if this fails...
fetch("/api/comments")
]);
// results = [
// { status: "fulfilled", value: Response },
// { status: "rejected", reason: Error },
// { status: "fulfilled", value: Response }
// ]
// Filter successes
const successful = results
.filter(r => r.status === "fulfilled")
.map(r => r.value);Promise.race — First to Finish
// Returns the first promise to settle (fulfill OR reject)
const result = await Promise.race([
fetch("/api/data"),
new Promise((_, reject) =>
setTimeout(() => reject(new Error("Timeout")), 5000)
)
]);
// Timeout pattern: either data arrives or 5s timeoutPromise.any — First Success
// Returns the first promise to FULFILL (ignores rejections)
const fastest = await Promise.any([
fetch("https://cdn1.example.com/data"),
fetch("https://cdn2.example.com/data"),
fetch("https://cdn3.example.com/data")
]);
// Gets data from whichever CDN responds first
// Only rejects if ALL promises reject (AggregateError)Decision Matrix
| Method | Use When | Fails When |
|---|---|---|
| Promise.all | Need ALL results, fail fast | Any rejects |
| Promise.allSettled | Want all results regardless | Never rejects |
| Promise.race | Need fastest response | First to settle rejects |
| Promise.any | Need first success | ALL reject |
Production Pattern: Resilient Fetching
async function resilientFetch(url, { timeout = 5000, retries = 3 } = {}) {
for (let i = 0; i < retries; i++) {
try {
return await Promise.race([
fetch(url),
new Promise((_, reject) =>
setTimeout(() => reject(new Error("Timeout")), timeout)
)
]);
} catch (err) {
if (i === retries - 1) throw err;
await new Promise(r => setTimeout(r, 1000 * Math.pow(2, i)));
}
}
}