Asyncintermediate
Promises Fundamentals
The Promise object representing an eventual result of an asynchronous operation, with its three states and chaining behavior.
A promise is an object representing a value that is not available yet.
A Promise is like a ticket you get at a dry cleaner: not the cleaned clothes yet, just a guarantee you'll either get them back or be told something went wrong.
Key Concepts
1
Three states, and the transition happens once.
pending -> fulfilled (with a value)
-> rejected (with a reason)2
Once settled it never changes. A promise that resolved cannot later reject, which is what makes it safe to
attach handlers at any time — including after it has already settled.
3
const p = new Promise((resolve, reject) => {
setTimeout(() => resolve('done'), 1000);
});4
p.then(v => console.log(v)); // 'done'5
then returns a new promise, and that is what makes chaining work:
then
6
fetchUser(id)
.then(user => fetchOrders(user.id)) // returns a promise
.then(orders => orders.length) // returns a value
.then(count => console.log(count))
.catch(err => console.error(err));7
Return a value and the next then receives it. Return a promise and the chain waits for it. That single
rule is the whole mechanism.
then
8
catch handles anything earlier in the chain. One handler at the end covers every step before it, which
is the improvement over callbacks needing a check at every level.
catch
9
.finally(() => hideSpinner()) // runs either way, passes the
// result through unchanged10
The mistake that breaks chains: forgetting to return.
.then(user => { fetchOrders(user.id); }) // returns undefined
.then(orders => ...) // receives undefined11
The inner promise is started and not awaited, so the next step runs immediately with nothing. The arrow
without braces returns implicitly, which is why the concise form is less error-prone here.
12
Creating one directly is rarer than it looks. Most promises come from APIs that already return them.
The constructor is for wrapping something callback-based:
13
const wait = (ms) => new Promise(r => setTimeout(r, ms));14
The anti-pattern to recognise.
new Promise(resolve => {
fetchData().then(d => resolve(d)); // pointless wrapper
});
fetchData(); // the same thing15
Promises run their executor immediately. The function passed to new Promise runs synchronously —
only the handlers are deferred. So creating a promise starts the work, whether or not anyone awaits it.
new Promise
16
What the interviewer is probing.1. "What are the three promise states?" Probing: the model. Stalls: "Done or not done."
Moves up: pending, fulfilled and rejected — and once settled it never changes, which is why a
promise cannot resolve twice.
17
2. "What does .then return?" Probing: chaining. Stalls: "The value." Moves up: a new
promise, which is what makes chaining work and why returning a value inside then passes it along.
18
3. "What happens if you forget to return inside .then?" Probing: the common chaining bug.
Stalls: "Nothing." Moves up: the next then receives undefined and does not wait for your inner
promise, so the chain races ahead.
19
4. "What is an unhandled rejection?" Probing: error propagation. Stalls: "A caught error."
Moves up: a rejected promise with no rejection handler — in Node it can terminate the process, so
every chain needs a catch.