Promises from First Principles
intermediate15 min readLesson 72 of 143
States, chaining, error propagation, and finally โ how promises replace callback pyramids and compose.
A promise is a value that may not exist yet. It has three states: pending โ fulfilled (with a value) or rejected (with an error) โ and once settled, never changes again.
Chaining
Every .then returns a new promise, which is what makes chains flat
instead of nested:
fetchJSON("/api/user")
.then((user) => fetchJSON("/api/orders/" + user.id))
.then((orders) => render(orders))
.catch((err) => showError(err)); // catches ANY step above
.finally(() => hideSpinner()); // runs either way
Three rules worth memorizing:
- Returning a value in
.thenfulfills the next promise with that value. - Returning a promise from
.thenmakes the chain wait for it. - A thrown error (or a rejected promise returned) skips forward to the nearest
.catchโ errors propagate like try/catch, through the whole chain.
Errors are values too
.catch(onRejected) is .then(undefined, onRejected). A .catch that returns
normally recovers the chain โ later .thens run. That is how fallback logic
works:
getFromCache(id)
.catch(() => getFromNetwork(id)) // fallback
.then(render);
finally
.finally(fn) runs on both outcomes and receives nothing โ it is for cleanup
(spinner off, lock released), not for the result.