Promises in Node.js
A Promise is an object representing a value that isn't ready yet — a placeholder for the eventual result (or failure) of an async operation. Promises replaced the callback convention as Node's primary async abstraction because they chain cleanly, unify error handling, and compose — letting you combine many async operations with one expression.
The three states
State | Meaning | Settled? |
|---|---|---|
pending | The operation is still in progress | No |
fulfilled | Completed successfully, has a value | Yes |
rejected | Failed, has a reason (an error) | Yes |
Consuming a promise
fetchUser(1)
.then((user) => console.log('got', user.name)) // fulfilled path
.catch((err) => console.error('failed', err)) // rejected path
.finally(() => console.log('done either way')) // always runsMethod | Runs when | Returns |
|---|---|---|
| Promise fulfills | A new promise (chainable) |
| Fulfills or rejects | A new promise |
| Promise rejects | A new promise |
| Settles either way | A pass-through promise |
Chaining: each then returns a new promise
The power of promises is that .then returns another promise, so steps line up flat. Return a value to pass it on; return a promise to wait for it first:
fetchUser(1) .then((user) => user.id) // return a value → next .then gets it .then((id) => fetchOrders(id)) // return a promise → chain waits for it .then((orders) => console.log(orders.length)) .catch((err) => console.error(err)) // one catch for the whole chain
Creating a promise
Most of the time you consume promises from APIs. When you must wrap a non-promise API (like a callback or an event), use the Promise constructor — calling resolve on success, reject on failure:
function delay(ms, value) {
return new Promise((resolve, reject) => {
if (ms < 0) return reject(new Error('negative delay'))
setTimeout(() => resolve(value), ms)
})
}
delay(100, 'hi').then(console.log) // 'hi' after 100msCombining promises
The static combinators are where promises outshine callbacks — running many operations together with precise semantics:
Combinator | Resolves when | Rejects when |
|---|---|---|
| ALL fulfill → array of values | ANY rejects (fails fast) |
| ALL settle → array of | Never — reports each outcome |
| The FIRST settles (ok or fail) | If the first to settle rejects |
| The FIRST to fulfill | If ALL reject ( |
// Run three in parallel, fail if any fails:
const [a, b, c] = await Promise.all([getA(), getB(), getC()])
// Run three, get every outcome regardless of failures:
const results = await Promise.allSettled([getA(), getB(), getC()])
results.forEach((r) => {
if (r.status === 'fulfilled') console.log(r.value)
else console.error(r.reason)
})