A Value You'll Get Later
JavaScript Promises
A Promise is a placeholder for a future value — the result of an async operation that hasn't finished yet.
What you'll learn
- Recognize Promise states (pending, fulfilled, rejected)
- Use `.then`, `.catch`, `.finally`
- Combine promises with `Promise.all` and friends
A Promise represents a value that isn’t here yet — the result of an async operation. A Promise is always in one of three states:
- Pending — operation in progress.
- Fulfilled — operation finished, value available.
- Rejected — operation failed, reason available.
Once fulfilled or rejected, a Promise is settled and never changes.
Creating a Promise
You usually consume Promises (from fetch, etc.) rather than create
them. But here’s the constructor for completeness:
const p = new Promise((resolve, reject) => {
setTimeout(() => {
const ok = Math.random() > 0.5;
if (ok) resolve("it worked!");
else reject(new Error("it failed"));
}, 100);
});
p
.then((value) => console.log("OK:", value))
.catch((err) => console.log("ERR:", err.message)); resolve(value) fulfills the Promise. reject(reason) rejects it.
Consuming With .then / .catch / .finally
The common case — chain on existing promises.
function delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
delay(50)
.then(() => "step 1")
.then((v) => v + " → step 2")
.then(console.log)
.catch((err) => console.error(err))
.finally(() => console.log("done")); .then(onFulfilled)runs when the Promise resolves..catch(onRejected)runs on rejection — catches errors from earlier in the chain..finally(fn)runs whether it resolved or rejected.
.then Returns a Promise
Each .then produces a new Promise — that’s why you can chain.
Returning a value from a .then callback resolves the next Promise
to that value:
Promise.resolve(2)
.then((n) => n * 5)
.then((n) => n + 1)
.then(console.log); // 11 If the callback returns a Promise, the chain waits for it before continuing.
Combining Multiple Promises
Promise.all — wait for all
Takes an array of Promises, resolves to an array of values once they’ve all resolved. Rejects fast if any one rejects.
function delay(ms, value) {
return new Promise((r) => setTimeout(() => r(value), ms));
}
Promise.all([delay(50, "a"), delay(100, "b"), delay(30, "c")])
.then((values) => console.log(values));
// ["a", "b", "c"] Promise.allSettled — wait for all, ignore failures
Waits for every Promise to settle. Returns an array of
{ status, value | reason } objects — never rejects.
Promise.race — first to settle wins
Resolves or rejects with whichever Promise settles first.
Promise.any — first SUCCESS wins
Like race, but waits for the first one to fulfill — ignoring
rejections unless they all reject.
Static Helpers: Promise.resolve / Promise.reject
Make an already-settled Promise:
const ok = Promise.resolve(42);
const bad = Promise.reject(new Error("boom"));
ok.then(console.log); // 42
bad.catch((e) => console.log(e.message)); // "boom" Useful for testing or “sometimes async, sometimes not” APIs.
Common Pitfalls
- Forgetting to return: in a
.then, you mustreturnthe next value or Promise. Otherwise the chain doesn’t see it. - Forgetting
.catch: an unhandled rejection logs a noisy warning. Always have a.catchsomewhere in your chain. - Mixing with callbacks: don’t try to “await” a Promise with
setTimeout polling. Use
.thenor, better,async/await.
Try It Yourself
Exercise
Chain Two Promises
function fetchUser(id) {
return Promise.resolve({ id, name: "Ada" });
}
// chain here
✅ Show solution
fetchUser(1)
.then(user => `User: ${user.name}`)
.then(line => console.log(line))
.catch(() => console.log("oops"));
Up Next
The syntax that makes Promise-chained code look like synchronous
code — async/await.