Learnitweb

Chaining Promises Using .then()

The Key Idea: .then() Returns a New Promise

This is extremely important:

Every .then() call returns a new promise.

Because of this:

  • We can call another .then() on the result.
  • Each .then() receives the value returned from the previous one.

This allows us to create a chain of asynchronous operations.

Step 1: Basic Promise Chain

Let’s start with a simple example.

calculateSquare(1)
  .then(value => {
    console.log(value);
  });

Output:

1

So far, nothing new.

Step 2: Adding Another .then()

Now let’s add another .then() right after the first one.

calculateSquare(1)
  .then(value => {
    console.log(value);
  })
  .then(value => {
    console.log(value);
  });

Output:

1
undefined

Why does this happen?

The second .then() receives the return value of the previous .then() callback.

But the first .then() does not return anything — and in JavaScript, that means:

return undefined;

So the second .then() receives undefined.

Returning a Value from .then()

Now let’s return something explicitly.

calculateSquare(1)
  .then(value => {
    console.log(value);
    return 25;
  })
  .then(value => {
    console.log(value);
  });

Output:

1
25

Now the second .then() receives the value returned by the first one.

Throwing an Error Inside .then()

What if something goes wrong?

We can throw an error inside a .then() callback.

calculateSquare(1)
  .then(value => {
    console.log(value);
    throw new Error("Something went wrong");
  })
  .then(value => {
    console.log(value);
  })
  .catch(error => {
    console.log(error.message);
  });

Output:

1
Something went wrong

What happened?

  • Throwing an error automatically rejects the promise
  • Control jumps to the nearest .catch()
  • The chain stops executing normal .then() handlers

Returning Another Promise from .then()

Now comes the most powerful part.

Instead of returning a value, we can return another promise.

calculateSquare(1)
  .then(value => {
    console.log(value);
    return calculateSquare(2);
  })
  .then(value => {
    console.log(value);
  });

Output:

1
4

Why does this work?

When you return a promise from .then():

  • JavaScript waits for that promise to resolve
  • The resolved value is passed to the next .then()

This allows clean and readable asynchronous chains.

Handling Rejected Promises in a Chain

Now let’s see what happens when an error occurs.

calculateSquare(1)
  .then(value => {
    console.log(value);
    return calculateSquare("wrong input");
  })
  .then(value => {
    console.log(value);
  })
  .catch(error => {
    console.log(error);
  });

Output:

1
Argument of type number is expected

Explanation:

  • The second call rejects the promise
  • The rejection skips all remaining .then() calls
  • The .catch() handler receives the error

Key Concept: Promise Chaining Flow

.then() → returns value → next then gets value
.then() → returns promise → waits for it
.then() → throws error → jumps to catch()