Promise Combinators
all, race, allSettled, any
LinkedIn Hook
Four static methods on the
Promiseconstructor —all,race,allSettled,any— decide whether your dashboard loads all-or-nothing, survives a flaky API, times out a slow request, or gracefully fails over to a backup CDN.Most developers only know
Promise.all, and that's the one that hurts them in production.Promise.allshort-circuits on the first rejection, which means one broken endpoint takes down the whole screen.Promise.allSettledwould have rendered the other three widgets and logged the failure.Promise.racewould have given you a clean timeout pattern in three lines.Promise.anywould have picked the fastest working CDN automatically.In this lesson you'll learn the exact semantics of each combinator, the one-word difference between
raceandany, what anAggregateErroris, and the copy-paste timeout pattern every backend engineer should have in their toolbox.Pick the wrong combinator and your entire page breaks over one bad request. Pick the right one and it self-heals.
Read the full lesson -> [link]
#JavaScript #InterviewPrep #Promises #AsyncJS #Frontend #CodingInterview #WebDevelopment
What You'll Learn
- The four Promise combinators and when each one is the correct choice
- How to build a timeout wrapper with
Promise.raceand pick the fastest CDN withPromise.any - What an
AggregateErroris and why it only appears withPromise.any
The Four Combinators at a Glance
JavaScript provides four static methods on the Promise constructor for handling multiple Promises. Think of them like different rules for a group project:
| Method | Resolves When | Rejects When | Use Case |
|---|---|---|---|
Promise.all | ALL fulfill | ANY ONE rejects | Need all results, fail fast |
Promise.race | First to settle (either way) | First to settle (if rejected) | Timeout pattern, fastest response |
Promise.allSettled | ALL settle (regardless of outcome) | Never rejects | Need all results, even failures |
Promise.any | First to FULFILL | ALL reject (AggregateError) | Fastest successful response |
Promise.all — All or Nothing
// Simulating API calls with different response times
const fetchUser = () =>
new Promise((resolve) => setTimeout(() => resolve({ name: "Rakibul" }), 300));
const fetchPosts = () =>
new Promise((resolve) => setTimeout(() => resolve(["Post 1", "Post 2"]), 500));
const fetchNotifications = () =>
new Promise((resolve) => setTimeout(() => resolve(5), 200));
// All three run in parallel, result arrives when ALL are done (~500ms)
async function loadDashboard() {
try {
const [user, posts, notifications] = await Promise.all([
fetchUser(),
fetchPosts(),
fetchNotifications(),
]);
console.log(user); // { name: "Rakibul" }
console.log(posts); // ["Post 1", "Post 2"]
console.log(notifications); // 5
} catch (error) {
console.error("One failed, all failed:", error);
}
}
Promise.all with One Failure (and allSettled to the Rescue)
const success1 = () => Promise.resolve("Data A");
const failure = () => Promise.reject(new Error("API down!"));
const success2 = () => Promise.resolve("Data C");
// Promise.all — one failure kills everything
Promise.all([success1(), failure(), success2()])
.then((results) => console.log(results)) // never runs
.catch((err) => console.error(err.message)); // "API down!"
// Promise.allSettled — gets ALL results regardless
Promise.allSettled([success1(), failure(), success2()])
.then((results) => {
console.log(results);
// [
// { status: "fulfilled", value: "Data A" },
// { status: "rejected", reason: Error("API down!") },
// { status: "fulfilled", value: "Data C" }
// ]
// Filter successes and failures separately
const successes = results.filter((r) => r.status === "fulfilled");
const failures = results.filter((r) => r.status === "rejected");
console.log(`${successes.length} succeeded, ${failures.length} failed`);
});
Promise.race — The Timeout Pattern
Promise.race resolves or rejects with whichever Promise settles first. The classic use case is implementing a timeout:
function fetchWithTimeout(url, timeoutMs) {
const fetchPromise = fetch(url);
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error(`Request timed out after ${timeoutMs}ms`)), timeoutMs);
});
// Whichever settles first wins
return Promise.race([fetchPromise, timeoutPromise]);
}
// Usage
async function getData() {
try {
const response = await fetchWithTimeout("https://api.example.com/data", 3000);
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error.message); // "Request timed out after 3000ms" or network error
}
}
Promise.any — First Success Wins
// Try multiple CDN mirrors — use whichever responds first successfully
async function loadScript() {
try {
const fastest = await Promise.any([
fetch("https://cdn1.example.com/lib.js"),
fetch("https://cdn2.example.com/lib.js"),
fetch("https://cdn3.example.com/lib.js"),
]);
console.log("Loaded from fastest CDN:", fastest.url);
} catch (error) {
// Only reaches here if ALL three fail
console.error("All CDNs failed:", error); // AggregateError
console.log(error.errors); // array of individual errors
}
}
Promise.any vs Promise.race — The Key Difference
const slow = new Promise((resolve) => setTimeout(() => resolve("slow"), 500));
const fastReject = new Promise((_, reject) => setTimeout(() => reject("fail"), 100));
// Promise.race: first to SETTLE wins (even if it's a rejection)
Promise.race([slow, fastReject])
.then((val) => console.log("race resolved:", val))
.catch((err) => console.log("race rejected:", err)); // "race rejected: fail"
// Promise.any: first to FULFILL wins (rejections are ignored until all fail)
Promise.any([slow, fastReject])
.then((val) => console.log("any resolved:", val)) // "any resolved: slow"
.catch((err) => console.log("any rejected:", err));
The one-word difference: race watches for the first settlement, any watches for the first fulfillment.
Common Mistakes
- Reaching for
Promise.allwhen you actually needPromise.allSettled— one unreliable endpoint then tanks the entire batch even though the other results were fine. - Confusing
Promise.raceandPromise.any—racealso rejects if the first settler is a rejection, so using it for "first success" quietly fails on a fast-failing Promise. - Forgetting that
Promise.anyrejects with anAggregateError(not a singleError) —err.messageis generic; the real reasons live onerr.errors.
Interview Questions
Q: What is the difference between Promise.all and Promise.allSettled?
Promise.allshort-circuits on the first rejection — if any Promise fails, the whole thing rejects.Promise.allSettledwaits for every Promise to settle and returns an array of{status, value/reason}objects, never rejecting. UseallSettledwhen you need results from all operations even if some fail.
Q: Explain Promise.race with a practical use case.
Promise.raceresolves or rejects with whichever Promise settles first. The most common use case is a timeout: race your actual fetch against asetTimeoutthat rejects. Whichever completes first determines the outcome.
Q: What is the difference between Promise.any and Promise.race?
Promise.racesettles with the first Promise to settle, whether fulfilled or rejected.Promise.anywaits for the first fulfillment, ignoring rejections.Promise.anyonly rejects if ALL Promises reject, throwing anAggregateErrorcontaining all the rejection reasons.
Q: What is an AggregateError?
An error type thrown when
Promise.anyrejects (all Promises failed). It has an.errorsproperty — an array containing every individual rejection reason.
Q: How would you implement a timeout using Promises?
Race the real operation against a Promise that rejects via
setTimeout:Promise.race([realPromise, new Promise((_, reject) => setTimeout(() => reject(new Error("timeout")), ms))]). Whichever settles first wins.
Quick Reference — Cheat Sheet
PROMISE COMBINATORS — QUICK MAP
+-----------------+----------------+-----------------------+
| Method | Resolves | Rejects |
+-----------------+----------------+-----------------------+
| Promise.all | All fulfill | Any one rejects |
| Promise.race | First settles | First settles (if rej)|
| Promise.allSet. | All settle | Never |
| Promise.any | First fulfills | All reject (Aggregate)|
+-----------------+----------------+-----------------------+
Picking one:
all -> need every result, fail fast
allSettled -> need every result, tolerate failures
race -> timeouts, first-to-finish wins
any -> fallback to first working source
Timeout pattern:
Promise.race([
realPromise,
new Promise((_, rej) =>
setTimeout(() => rej(new Error("timeout")), ms))
])
AggregateError:
Thrown ONLY by Promise.any when all reject.
Access individual reasons via err.errors (array).
Previous: async/await — Syntactic Sugar Over Promises Next: Error Handling in Async Code
This is Lesson 3.9 of the JavaScript Interview Prep Course — 14 chapters, 87 lessons.