Navigate
Search topics, hooks, and fundamentals
From nested callback pyramids to clean promise chains. Promises are the foundation of modern async JavaScript.
When async operations depend on each other, callbacks nest deeper and deeper — the infamous "pyramid of doom":
// Callback Hell — deeply nested, hard to read
getUser(userId, (user) => {
getOrders(user.id, (orders) => {
getOrderDetails(orders[0].id, (details) => {
getShipping(details.trackingId, (shipping) => {
console.log(shipping.status);
// 4 levels deep — and error handling is a nightmare
});
});
});
});Watch a sequence of dependent async operations. Compare the callback nesting with the flat promise chain:
A Promise represents a value that will be available later. Chaining .then() keeps the code flat:
// Promises — flat chain, much easier to follow
getUser(userId)
.then(user => getOrders(user.id))
.then(orders => getOrderDetails(orders[0].id))
.then(details => getShipping(details.trackingId))
.then(shipping => console.log(shipping.status))
.catch(error => console.error("Something failed:", error));When you need to run multiple promises together:
// Promise.all — run multiple promises in parallel
const [user, settings, notifications] = await Promise.all([
fetchUser(), // starts immediately
fetchSettings(), // starts immediately
fetchNotifications() // starts immediately
]);
// All three run at the same time!
// Resolves when ALL complete, rejects if ANY fail// Promise.race — first one to finish wins
const result = await Promise.race([
fetchFromServer(),
timeout(5000), // reject after 5 seconds
]);
// Useful for implementing timeouts.then() chainsPromise.all runs promises in parallel, resolves when all completePromise.race resolves with the first promise to settle.catch() handles errors anywhere in the chain