Question presented to candidate: "Explain what a Promise actually is — not just how to use .then() — and why it was worth adding to the language on top of plain callbacks."
What a strong answer should cover:
- A Promise is an object representing the eventual result of an async operation — it exists in one of exactly three states: pending, fulfilled (with a value), or rejected (with a reason), and once fulfilled or rejected, it is permanently settled — it can never change state again.
.then(onFulfilled, onRejected)registers callbacks for the eventual outcome and itself returns a new Promise, which is what makes chaining (.then().then()) possible — each.then()can return a value, or another Promise, and the chain waits for it..catch(fn)is exactly.then(undefined, fn)— syntactic sugar for handling a rejection, and critically, it catches a rejection from any earlier step in the chain, not just the immediately preceding one, which is the main ergonomic win over per-step callback error handling.Promise.all([...])runs multiple Promises concurrently and resolves when all succeed (or rejects as soon as any one does);Promise.allSettled([...])waits for all of them regardless of individual success/failure and reports each outcome — a distinct, commonly-confused-with-alltool.- Promise
.then/.catchcallbacks are scheduled as microtasks — they always run after the current synchronous code finishes and afterprocess.nextTick's queue, but before the next macrotask (asetTimeout, an I/O callback) — this timing guarantee is itself a real, testable claim, not just a style preference. async/awaitis not a different mechanism — anasyncfunction always returns a Promise, andawaitis syntax for consuming one; understanding Promises underneath is what makesasync/await's behavior (including error propagation) predictable rather than magic.
Clarifying questions expected:
- "Does the interviewer want the mechanics (states, microtask timing) or just usage patterns?" — these are different depths of the same topic.
- "Is error handling for one step or the whole chain the actual concern here?" — decides whether to reach for a single trailing
.catchor a.then(ok, err)pair at one step.
Code / implementation expected: Yes — a chain with a deliberate mid-chain rejection actually caught by a single trailing .catch, plus a real timing check proving the microtask-before-macrotask ordering, is the concrete deliverable.