Chaining Promises Is the Least Important Part
How returning a promise from inside .then() chains two promises together, why the value flows forward automatically, and why the flattened shape people get excited about barely matters.
Here's the actual idea this post teaches, in one sentence: chaining a promise just means returning a new promise from inside a .then() handler, which makes the next step wait for it and receive its value automatically, and the flat, non-nested shape everyone gets excited about is the least important thing about it.
The Same Pyramid, Rewritten
Three genuine dependencies, three levels of nesting, no way around it with plain callbacks:
getBasePrice('sofa-142', function (base) {
getDiscount(base, function (discounted) {
getFinalTotal(discounted, function (total) {
console.log(`Final total: $${total.toFixed(2)}`);
});
});
});Rewrite each function to return a promise instead of taking a callback, and the exact same sequence looks like this:
function fakeAsync(value) {
return new Promise((resolve) => setTimeout(() => resolve(value), 300));
}
function getBasePrice(sku) {
return fakeAsync(120);
}
function getDiscount(base) {
return fakeAsync(base * 0.9);
}
function getFinalTotal(discounted) {
return fakeAsync(discounted * 1.08);
}
getBasePrice('sofa-142')
.then((base) => getDiscount(base))
.then((discounted) => getFinalTotal(discounted))
.then((total) => console.log(`Final total: $${total.toFixed(2)}`));No nesting. Just a straight vertical line.
How the Chain Actually Links Together
This isn't automatic magic. It comes down to one specific rule: whatever you return from inside a .then() handler becomes what the next .then() waits for.
getDiscount(base) returns a promise. Returning it from inside the first .then() tells the chain: don't move on yet, wait for this one too. The second .then() only runs once that returned promise settles.
That's the whole mechanism. Each step's resolved value flows straight into the next step's callback, as an argument, with nothing extra written to carry it there.
The Part That Doesn't Actually Matter Much
Here's the thing worth saying plainly: that flattened, non-nested shape is the least important thing a promise chain gives you.
It's not nothing. A vertical chain is genuinely easier to scan than three closing braces stacked on top of each other. But the pyramid was never actually the disease, remember. It was always just the most visible symptom.
What actually matters is everything from the last two posts: the value can't be changed after the fact, an error anywhere in the chain has exactly one place to land, and each step is genuinely guaranteed to run once. A chain of thunks, or a chain of plain callbacks, can look just as flat as this. Neither one gives you any of those guarantees.
It's easy to get excited the first time you see a promise chain replace a pyramid and think that's the whole win. It isn't. The shape changed. The trust is what's actually new.
There are better tools than a long .then() chain for real flow control, and this series gets to them soon. For now, the mechanism is simple: return a promise, and the chain waits for it.
Keep reading