Prompt
Create a promise chain that:
- Fetches a user (simulated: resolve with {id:1, name:'Alice'})
- Then fetches their posts (simulated: resolve with ['post1', 'post2'])
Log each step. Assign the chain to
const chain.
Solution
Chaining exists to keep sequential async work flat — the alternative is nesting each request inside the previous callback, which is exactly the pyramid promises were invented to kill. The mechanics that make it work: every .then returns a new promise, and what you return from the callback decides what that promise resolves with. Return a plain value and it's wrapped; return a promise — return fetchPosts(user.id) — and the chain adopts it, so the next .then waits for the posts request to settle. That one return is the whole exercise: drop it and the second .then fires immediately with undefined, a bug that type-checks and only surfaces at runtime.
The other structural win is error handling: a single .catch() appended to the end observes a rejection from any step, because rejections propagate down the chain until something handles them. Nested callbacks need per-level handling; a flat chain needs one.
Red flag: nesting .then inside .then (fetchUser().then(u => { fetchPosts(u.id).then(...) })). It works, but it recreates callback hell, orphans the inner promise from the outer chain, and means the trailing .catch never sees the inner failure. Interviewers read it as "uses promises, doesn't understand them."
Say it: "Every .then returns a new promise; returning the next async call from the callback is what sequences the chain, and one .catch at the end observes a failure from any step."