JavaScript gives us four static methods on the Promise object to handle multiple Promises at once. Each behaves differently — knowing when to use which is a common interview question.
Promise.all()
Takes an array of Promises and returns a single Promise that resolves with an array of all results. If any one rejects, the whole thing rejects immediately with that error.
Use case: When we need ALL results and any failure means we can’t proceed.
const [users, posts, settings] = await Promise.all([
fetch("/api/users").then(r => r.json()),
fetch("/api/posts").then(r => r.json()),
fetch("/api/settings").then(r => r.json())
]);
// All three must succeed, or we get an error
// If posts API fails, we don't get users or settings either
// What happens on rejection
Promise.all([
Promise.resolve("A"),
Promise.reject("B failed!"),
Promise.resolve("C") // this still runs, but result is ignored
]).catch(err => console.log(err)); // "B failed!"
Promise.allSettled()
Waits for all Promises to settle (either resolve or reject). Never rejects itself. Returns an array of objects with status, value (if fulfilled), or reason (if rejected).
Use case: When we want to try everything and handle successes and failures individually.
const results = await Promise.allSettled([
fetch("/api/users").then(r => r.json()),
fetch("/api/posts").then(r => r.json()),
fetch("/api/broken-endpoint").then(r => r.json())
]);
// results:
// [
// { status: "fulfilled", value: [...users] },
// { status: "fulfilled", value: [...posts] },
// { status: "rejected", reason: Error("404") }
// ]
// We can handle each individually
results.forEach(result => {
if (result.status === "fulfilled") {
console.log("Got:", result.value);
} else {
console.log("Failed:", result.reason);
}
});
Promise.race()
Returns the result of whichever Promise settles first — whether it resolves or rejects. The rest are ignored (but still run in the background).
Use case: Timeouts, picking the fastest response.
// Implementing a timeout for a fetch request
const result = await Promise.race([
fetch("/api/data").then(r => r.json()),
new Promise((_, reject) =>
setTimeout(() => reject("Timeout!"), 5000)
)
]);
// If fetch takes longer than 5 seconds, we get "Timeout!" error
// First to settle (even if it's a rejection)
Promise.race([
new Promise(resolve => setTimeout(() => resolve("slow"), 2000)),
new Promise((_, reject) => setTimeout(() => reject("fast error"), 500))
]).catch(err => console.log(err)); // "fast error" — rejection settled first
Promise.any()
Returns the result of the first Promise to resolve. It ignores rejections entirely. Only rejects if all Promises reject — with an AggregateError.
Use case: Trying multiple sources, we only need one to work.
// Try multiple CDN servers, use whichever responds first
const data = await Promise.any([
fetch("https://cdn1.example.com/data.json"),
fetch("https://cdn2.example.com/data.json"),
fetch("https://cdn3.example.com/data.json")
]);
// Uses the first successful response, ignores any that fail
// All reject → AggregateError
Promise.any([
Promise.reject("Error 1"),
Promise.reject("Error 2"),
Promise.reject("Error 3")
]).catch(err => {
console.log(err); // AggregateError: All promises were rejected
console.log(err.errors); // ["Error 1", "Error 2", "Error 3"]
});
Quick cheat sheet
| Method | Resolves when | Rejects when |
|---|---|---|
Promise.all | ALL resolve | ANY one rejects |
Promise.allSettled | ALL settle | Never rejects |
Promise.race | First to settle | First to settle (if it rejects) |
Promise.any | First to resolve | ALL reject |
In simple language: use all when every result matters, allSettled when you want to try everything regardless of failures, race when speed matters, and any when you just need one success from multiple attempts.