JavaScript + Node.js track

Lesson 15 · Part 4: Async

Promises

`Promise`, `then`/`catch`, chaining and `all`/`race`

Part 4: Async2 min readFree lesson

Level: Intermediate | Players: 14 callbacks and timers

Learning Objectives

  • Know the three states of Promise (pending, fulfilled, rejected).
  • You can create a Promise directly with new Promise.
  • Process the results as then, catch, and finally.
  • Chaining can flatten the callback hell.
  • Know the difference between Promise.all and Promise.race.

1. What is a Promise?

A Promise is “a box that holds the result of an operation to be completed at some point in the future.” There are three states:

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

If you call resolve, it will be fulfilled, and if you call reject, it will be rejected. Once the status is set, it cannot be changed.

2. then / catch / finally

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

The value returned from the callback of then goes into the next argument of then. If an error occurs, nearby catch catches it.

3. Chaining

If we rewrite the callback hell example as a Promise , it becomes flat.

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

If a Promise is returned within then, the next then will wait until it completes.

4. Promise.all / Promise.race

  • Promise.all([p1, p2, ...]): All must succeed to succeed, if even one fails, it fails. The result is an array.
  • Promise.race([p1, p2, ...]): Adopt the result determined first (success/failure).
  • Promise.allSettled: Wait until everything is finished and return each status object array.

Core example

file Contents covered
01_new_promise.js Create your own with new Promise
02_then_catch.js Using then/catch/finally
03_chaining.js Sequential execution with chaining
04_all_race.js Promise.all / Promise.race

⚠️ Common Mistakes

  1. then does not return a value, so undefined is received in the next then.
  2. Unhandled rejection occurs when used without catch.
  3. Forgetting that if even one of Promise.all fails, it is a total failure.
  4. I do not know that errors thrown within new Promise are automatically rejected.
  5. Thinking that a Promise is “lazy” without knowing that it is executed immediately.

❓ Frequently Asked Questions (FAQ)

Q1. Can resolve/reject be called immediately? A. Yes. Still, the then callback runs asynchronously.

Q2. Difference between catch and then's second argument? A. onRej of then(onFul, onRej) does not catch errors thrown by onFul of the same then. catch is safer.

Q3. What if you return a Promise within a Promise? A. It is automatically resolved and then the value is passed to the next step.

Example files

The runnable files used in this lesson. Copy them into your own project and experiment.

src/01_new_promise.jsJavaScript
/**
 *Express asynchronous operations 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.jsJavaScript
/**
 *It shows 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 ends"));

fetchUser(-1)
  .then((user) => console.log(user))
  .catch((err) => console.error("Error:", err.message))
  .finally(() => console.log("End of second request"));
src/03_chaining.jsJavaScript
/**
 *Execute asynchronous steps sequentially with promise 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.jsJavaScript
/**
 *Comparing 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);
});

Assignment

1. delay function

Write delay(ms) to return a Promise that is resolved after ms milliseconds.

2. Parallel summation

Receive three asynchronous numeric values as Promise.all and print the sum.

The reference solution is shown below.

Show the reference solution

Try the assignment yourself first — comparing your attempt with a working solution is where most of the learning happens.

homework_01.jsJavaScript
/**
 *A Promise that is resolved after waiting for a given amount of time.
 *@param {number} ms wait milliseconds
 * @returns {Promise<void>}
 */
function delay(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

console.log("start");
delay(500).then(() => console.log("0.5 seconds passed"));
homework_02.jsJavaScript
/**
 *It takes three asynchronous numbers in parallel and outputs 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("Total:", sum);
  });

Learn this lesson with a mentor

Work through the JavaScript + Node.js track on your own, or join a guided cohort at our Pitampura campus and online.

Call NowEnroll Now