Learnitweb

Handling Promise Rejections Using .then() and .catch()

Using .then() with One or Two Arguments

The .then() method can accept two arguments:

then(onFulfilled, onRejected)
  • onFulfilled → called when the promise is resolved
  • onRejected → called when the promise is rejected

So far, we mostly used .then() with only one argument, which handles successful cases.

Example: Handling Both Success and Failure

Let’s use our familiar calculateSquare function.

calculateSquare(2)
  .then(
    value => {
      console.log(value);
    },
    error => {
      console.error(error);
    }
  );

This works correctly:

  • If the promise resolves → onFulfilled runs
  • If the promise rejects → onRejected runs

However, this approach has a limitation.

The Hidden Problem

Let’s introduce an error inside the success handler.

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

Output:

Something went wrong

So far, everything seems fine.

But What Happens If the Error Occurs Later?

Now let’s move the error into the next .then().

calculateSquare(2)
  .then(value => {
    console.log(value);
    return calculateSquare(3);
  })
  .then(value => {
    throw new Error("Something went wrong");
  });

Result:

Uncaught (in promise) Error: Something went wrong

Why did this happen?

Because:

  • The error occurs inside the second .then()
  • There is no error handler attached after it
  • The rejection is not caught

This is a common mistake when working with promises.

Fixing the Problem Using .then(undefined, onRejected)

To catch this error, we can add another .then() and pass undefined as the first argument.

calculateSquare(2)
  .then(value => {
    console.log(value);
    return calculateSquare(3);
  })
  .then(value => {
    throw new Error("Something went wrong");
  })
  .then(
    undefined,
    error => {
      console.error(error.message);
    }
  );

Now the error is properly handled.

A Better Way: Using .catch()

Because handling errors separately is very common, JavaScript provides a cleaner method called .catch().

The .catch() method is simply a shortcut for:

.then(undefined, onRejected)

Rewriting the Example Using .catch()

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

This code behaves exactly the same but is much easier to read.

Returning a Rejected Promise

Instead of throwing an error, we can also return a rejected promise.

calculateSquare(2)
  .then(value => {
    console.log(value);
    return Promise.reject("Something went wrong");
  })
  .catch(error => {
    console.error(error);
  });

This has the same effect:

  • The promise becomes rejected
  • Control moves directly to .catch()

Important Rule to Remember

A promise becomes rejected in two cases:

  1. An error is thrown inside a .then() callback
  2. A rejected promise is returned

In both cases, execution jumps directly to .catch().

Summary

Let’s summarize what we learned:

  • .then() can take two functions: success and failure handlers.
  • Errors thrown inside .then() are converted into rejected promises.
  • If no error handler exists, the error becomes unhandled.
  • .catch() is a cleaner and more readable way to handle errors.
  • Returning a rejected promise behaves the same as throwing an error.
  • Error handling should always be placed at the end of a promise chain.