Promise Chaining & Promise.all / Promise.race
Promise chaining lets you sequence async operations cleanly — each .then() returns a new promise. Promise.all runs multiple promises in parallel. Promise.race returns the first to complete.
Promise Chaining & Combinators
- .then() returns a new promise — enables chaining: fetch().then().then().then()
- Each .then() receives the return value of the previous .then()
- Promise.all([p1, p2, p3]) — Run in parallel, resolve when ALL complete. Fails if ANY rejects
- Promise.race([p1, p2, p3]) — Returns first promise to settle (fastest wins)
- Promise.allSettled([...]) — Like all but never rejects. Returns status of each: fulfilled or rejected
- Promise.any([...]) — Returns first FULFILLED promise (ignores rejections)
Promise Chaining Code
// Promise chaining — flat, not nested!
function getUser(id) {
return new Promise(resolve =>
setTimeout(() => resolve({ id, name: "Alice" }), 500)
);
}
function getOrders(userId) {
return new Promise(resolve =>
setTimeout(() => resolve([{ id: 101, item: "Laptop", userId }]), 500)
);
}
function getDetails(orderId) {
return new Promise(resolve =>
setTimeout(() => resolve({ id: orderId, status: "Shipped" }), 500)
);
}
// Chaining — clean and flat!
getUser(1)
.then(user => {
console.log("User:", user.name);
return getOrders(user.id);
})
.then(orders => {
console.log("Orders:", orders);
return getDetails(orders[0].id);
})
.then(details => {
console.log("Details:", details);
})
.catch(error => {
console.error("Any error caught here:", error);
});
// Promise.all — parallel execution
const p1 = new Promise(resolve => setTimeout(() => resolve("API 1"), 1000));
const p2 = new Promise(resolve => setTimeout(() => resolve("API 2"), 500));
const p3 = new Promise(resolve => setTimeout(() => resolve("API 3"), 800));
Promise.all([p1, p2, p3])
.then(results => console.log("All done:", results))
.catch(err => console.error("One failed:", err));
// ["API 1", "API 2", "API 3"] — in order, not speed order
// Promise.race — first to finish wins
Promise.race([p1, p2, p3])
.then(fastest => console.log("Fastest:", fastest));
// "API 2" (500ms was fastest)
// Promise.allSettled — never rejects
Promise.allSettled([p1, Promise.reject("Error!"), p3])
.then(results => {
results.forEach(r => console.log(r.status, r.value || r.reason));
});Tip
Tip
Use Promise.all for independent requests that can run in parallel (fetching user + posts simultaneously). Use sequential await only when the second request depends on the first (fetch user, then fetch user's posts).
Promise.all for parallel (fail fast). allSettled for audit. race for timeout. any for first success.
Common Mistake
Warning
Using Promise.all when any single failure should be tolerated. Promise.all rejects if ANY promise fails. Use Promise.allSettled to get results of all promises regardless of individual failures.
Practice Task
Note
Promise combinators: (1) Use Promise.all to fetch 3 API endpoints simultaneously. (2) Use Promise.race to implement a timeout. (3) Use Promise.allSettled to handle partial failures gracefully.
Quick Quiz
Key Takeaways
- Promise chaining lets you sequence async operations cleanly — each.
- .then() returns a new promise — enables chaining: fetch().then().then().then()
- Each .then() receives the return value of the previous .then()
- Promise.all([p1, p2, p3]) — Run in parallel, resolve when ALL complete. Fails if ANY rejects