JavaScript Promises

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.

6 min read Level 3/5 #promises#async#then
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:

A new Promise script.js
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));
▶ Preview: console

resolve(value) fulfills the Promise. reject(reason) rejects it.

Consuming With .then / .catch / .finally

The common case — chain on existing promises.

Chaining handlers script.js
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"));
▶ Preview: console
  • .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:

Values flow through the chain script.js
Promise.resolve(2)
  .then((n) => n * 5)
  .then((n) => n + 1)
  .then(console.log); // 11
▶ Preview: console

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.

Promise.all script.js
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"]
▶ Preview: console

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:

Already-settled promises script.js
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"
▶ Preview: console

Useful for testing or “sometimes async, sometimes not” APIs.

Common Pitfalls

  • Forgetting to return: in a .then, you must return the next value or Promise. Otherwise the chain doesn’t see it.
  • Forgetting .catch: an unhandled rejection logs a noisy warning. Always have a .catch somewhere in your chain.
  • Mixing with callbacks: don’t try to “await” a Promise with setTimeout polling. Use .then or, better, async/await.

Try It Yourself

Exercise

Chain Two Promises

Difficulty 2/5~5 min
Given a function `fetchUser(id)` that returns a promise resolving to `{ id, name: "Ada" }`, write a chain that: 1. fetches the user 2. transforms the result into the string `"User: Ada"` 3. logs that string 4. logs `"oops"` if anything in the chain fails Use only `.then` / `.catch` (no async/await yet).
solution.js
function fetchUser(id) {
  return Promise.resolve({ id, name: "Ada" });
}

// chain here
0tests will run
✅ 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.

JavaScript async/await →