← Back to JavaScript series
🀝
Async
Intermediate Β· Prerequisite: 14_Callbacks_and_Timers

15. Promise

A Promise is "a box that will eventually hold the result of an async operation". It has three states.

Promisethencatchasync
Duration
⏱ ~1.5 hours
Level
πŸ“Š Intermediate
Prerequisite
🎯 Lecture 14
OUTCOME
A Promise is "a box that will eventually hold the result of an async operation". It has three states.

What you'll learn

  • 1Know the three Promise states (pending, fulfilled, rejected).
  • 2Create your own Promise with `new Promise`.
  • 3Handle results with `then`, `catch`, `finally`.
  • 4Flatten callback hell with chaining.
  • 5Tell `Promise.all` and `Promise.race` apart.

Overview

A Promise is "a box that will eventually hold the result of an async operation". It has three states.

Core Concepts

1. What is a Promise?

A Promise is "a box that will eventually hold the result of an async operation". It has three states.

  • pending: not finished yet
  • fulfilled: success β€” has a value
  • rejected: failure β€” has a reason (error)
javascript
const p = new Promise((resolve, reject) => {
  setTimeout(() => resolve(42), 100);
});

Calling `resolve` settles it as fulfilled; `reject` settles it as rejected. Once settled, the state never changes again.

2. then / catch / finally

javascript
p.then((value) => console.log(value))
 .catch((err) => console.error(err))
 .finally(() => console.log("done"));

Whatever a `then` callback returns is passed to the next `then`. Errors flow into the nearest `catch`.

3. Chaining

The callback-hell example rewritten with Promises becomes flat.

javascript
step("1").then(() => step("2")).then(() => step("3"));

If a `then` returns a Promise, the next `then` waits for it to settle.

4. Promise.all / Promise.race

  • `Promise.all([p1, p2, ...])`: succeeds only if all succeed; rejects on the first failure. Result is an array.
  • `Promise.race([p1, p2, ...])`: settles with the first one to settle (either way).
  • `Promise.allSettled`: waits for all to settle and returns an array of state objects.

Examples

FileWhat it covers
01_new_promise.jsBuilding a Promise directly
02_then_catch.jsUsing then/catch/finally
03_chaining.jsSequential execution by chaining
04_all_race.jsPromise.all / Promise.race

src/01_new_promise.js

javascript
/**
 * Represent an async operation with new Promise.
 */
const promise = new Promise((resolve, reject) => {
  const ok = Math.random() > 0.3;
  setTimeout(() => {
    if (ok) resolve("success!");
    else reject(new Error("failure..."));
  }, 200);
});

promise
  .then((value) => console.log("result:", value))
  .catch((err) => console.error("error:", err.message));

src/02_then_catch.js

javascript
/**
 * Show the flow of then / catch / finally.
 */
function fetchUser(id) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (id <= 0) reject(new Error("invalid ID"));
      else resolve({ id, name: "Jimin" });
    }, 100);
  });
}

fetchUser(1)
  .then((user) => console.log("user:", user))
  .catch((err) => console.error(err.message))
  .finally(() => console.log("request finished"));

fetchUser(-1)
  .then((user) => console.log(user))
  .catch((err) => console.error("error:", err.message))
  .finally(() => console.log("second request finished"));

src/03_chaining.js

javascript
/**
 * Run async steps sequentially via chaining.
 */
function step(name, ms) {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log(`${name} done`);
      resolve(name);
    }, ms);
  });
}

step("A", 100)
  .then((prev) => step(`B(after ${prev})`, 100))
  .then((prev) => step(`C(after ${prev})`, 100))
  .then((last) => console.log("final:", last));

src/04_all_race.js

javascript
/**
 * Compare Promise.all and Promise.race.
 */
function delay(ms, value) {
  return new Promise((resolve) => setTimeout(() => resolve(value), ms));
}

Promise.all([delay(100, "A"), delay(200, "B"), delay(150, "C")]).then((values) => {
  console.log("all:", values);
});

Promise.race([delay(100, "X"), delay(50, "Y"), delay(80, "Z")]).then((value) => {
  console.log("race winner:", value);
});

Common Mistakes

  1. Not returning a value in `then` and getting undefined in the next `then`.
  2. Skipping `catch` and triggering an unhandled rejection.
  3. Forgetting that `Promise.all` fails as soon as one input fails.
  4. Not realizing that throwing inside a `new Promise` executor is automatically converted to reject.
  5. Thinking Promises are "lazy" β€” they start running as soon as they're created.

FAQ

Q1. Can resolve/reject be called immediately?

Yes β€” but then-callbacks still run asynchronously.

Q2. Difference between catch and the second argument of then?

`then(onFul, onRej)`'s `onRej` does not catch errors thrown inside `onFul` on the same `then`. `catch` is safer.

Q3. What if I return a Promise inside another Promise?

It unwraps automatically β€” the next `then` receives the inner value.

Practice

  1. A `delay(ms)` Promise wrapper around setTimeout.
  2. Use Promise.all to run several tasks in parallel.

homework/README.md

## 1. delay β€” Write `delay(ms)` that returns a Promise resolving after `ms` milliseconds.

## 2. Parallel sum β€” Take three async numbers via Promise.all and print their sum.

See the `answer/` directory for solutions.

homework/answer/homework_01.js

javascript
/**
 * A Promise that resolves after the given delay.
 * @param {number} ms milliseconds to wait
 * @returns {Promise<void>}
 */
function delay(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

console.log("start");
delay(500).then(() => console.log("500ms elapsed"));

homework/answer/homework_02.js

javascript
/**
 * Fetch three async numbers in parallel and print the sum.
 */
function asyncNumber(n, ms) {
  return new Promise((resolve) => setTimeout(() => resolve(n), ms));
}

Promise.all([asyncNumber(10, 100), asyncNumber(20, 150), asyncNumber(30, 80)])
  .then((nums) => {
    const sum = nums.reduce((a, b) => a + b, 0);
    console.log("sum:", sum);
  });

Next Lecture

[16_async_await](../16_async_await/) β€” Cleaner syntax for Promises.

Example code / lecture materials

All lecture materials and example code are openly available on GitHub.

View on GitHub β†—