Promises Deep Dive
Promise states, chaining, static methods, error handling
Promise States
Three states, settle once, one-way.
new Promise((resolve, reject) => {
/* pending */
resolve("done") // → fulfilled
// reject("err") // → rejected
})
new Promise((r) => {
r("first")
r("second")
}) // "first" — second ignored
Chaining
Each .then returns new promise. Rejections skip to nearest .catch.
fetch("/api/user/1")
.then((r) => {
if (!r.ok) throw Error("HTTP " + r.status)
return r.json()
})
.then((user) => fetch("/api/posts?userId=" + user.id))
.then((r) => r.json())
.catch((err) => console.error(err))
.finally(() => hideLoader())
Put .catch before .finally. Errors in .finally aren't caught by .catch after.
Static Methods
Promise.withResolvers()
External resolve/reject — clean for callback wrapping.
const { promise, resolve, reject } = Promise.withResolvers()
fs.readFile("data.txt", "utf-8", (err, data) =>
err ? reject(err) : resolve(data)
)
await promise
See It In Action
See promise chaining in action — each .then receives the previous return value:
1Promise.resolve(1)2.then(x => x * 2)3.then(x => x + 3)4.then(x => `Result: ${x}`)5.then(console.log)6.catch(console.error)Each `.then()` transforms the value and passes it to the next. Return a value (not a promise) and the next `.then()` receives it immediately. This is how you build sequential async pipelines.
See It In Action
1function myPromiseAll(iterable) {2const promises = Array.from(iterable)3const results = new Array(promises.length)4let settled = 05 6return new Promise((resolve, reject) => {7promises.forEach((p, i) => {8Promise.resolve(p)9.then((val) => {10results[i] = val11settled++12if (settled === promises.length) resolve(results)13})14.catch(reject) // Reject immediately on first failure15})16})17}18 19// Usage — resolves with [1, 2, 3]20const p1 = Promise.resolve(1)21const p2 = Promise.resolve(2)22const p3 = Promise.resolve(3)23myPromiseAll([p1, p2, p3]).then(console.log)24 25// Usage — rejects immediately26const failing = Promise.reject("oops")27myPromiseAll([p1, failing, p3]).catch((err) => console.error("Caught:", err))`myPromiseAll`mirrors`Promise.all`: wraps each value with `Promise.resolve`, collects results in input order, resolves the outer promise when all complete, and rejects immediately on the first rejection — a classic fail-fast pattern.