Preparation

Read this introduction before the session. It explains the concepts we'll practice during the session.


The Problem: Callback Hell

Last week you wrote code like this:

validateOrder(order, (err, validation) => {
  if (err) return console.error(err);

  calculateTotal(order, (err, total) => {
    if (err) return console.error(err);

    checkStock(order, (err, stock) => {
      if (err) return console.error(err);

      processPayment(order, total, (err, receipt) => {
        if (err) return console.error(err);
        // Finally done... but look at this pyramid!
      });
    });
  });
});

This is called callback hell - deeply nested callbacks that are hard to read and maintain. Each new step adds another level of indentation. Error handling is repetitive. The code grows sideways instead of downward.

Promises solve this.


What is a Promise?

A Promise is an object representing an operation that hasn't completed yet. Think of it like an order ticket at a cafe:

  1. You place an order and receive a ticket (the Promise)

  2. The ticket promises you'll get coffee eventually

  3. Two outcomes: you get your coffee (resolved) or they're out (rejected)

📚 Glossary: Promise An object representing the eventual completion (or failure) of an asynchronous operation. A Promise is always in one of three states: pending, fulfilled (resolved), or rejected.


Consuming Promises: .then() and .catch()

When you have a Promise, you can attach callbacks using .then() and .catch():

  • .then() runs when the Promise resolves (succeeds)

  • .catch() runs when the Promise rejects (fails)

📚 Glossary: resolve / reject A Promise "resolves" when the operation succeeds, passing the result to .then(). It "rejects" when the operation fails, passing the error to .catch().


Chaining Promises

The magic of Promises: .then() returns a new Promise, so you can chain them:

No more nesting! The code flows downward, and one .catch() handles all errors.

📚 Glossary: then / catch .then(callback) schedules a callback to run when a Promise resolves. .catch(callback) schedules a callback to run when a Promise rejects. Both return new Promises, enabling chaining.


Creating Promises

You can create your own Promises using new Promise():

The Promise constructor takes a function with two parameters:

  • resolve - call this when the operation succeeds

  • reject - call this when the operation fails


async/await: Even Cleaner Syntax

async/await is syntactic sugar over Promises - it makes async code look synchronous:

  • async before a function makes it return a Promise

  • await pauses execution until a Promise resolves

  • The code reads top-to-bottom, like synchronous code

📚 Glossary: async / await async declares a function that returns a Promise. await pauses execution until a Promise settles, then returns its resolved value. Only works inside async functions.


Error Handling with try/catch

With async/await, you handle errors using try/catch:

This is the same pattern as synchronous error handling - familiar and readable.


Promise.all: Parallel Operations

Sometimes you want to run multiple operations at once:

Promise.all() takes an array of Promises and returns a Promise that resolves when ALL of them resolve.

📚 Glossary: Promise.all Takes an array of Promises and returns a single Promise that resolves when all input Promises resolve (with an array of results), or rejects when any input Promise rejects.


Summary

Term
Meaning

Promise

Object representing future completion/failure

resolve

Promise succeeded, pass result to .then()

reject

Promise failed, pass error to .catch()

.then()

Handle successful result

.catch()

Handle error

async

Makes function return a Promise

await

Pause until Promise resolves

Promise.all

Run multiple Promises in parallel


Pre-Reading (Optional)

If you want to go deeper, read these MDN pages:


The Tea Shop API

During the session you'll work with a real API:

Example:

Last updated