Handling Asynchronous Errors in the Promise API

Introduction

In modern Express applications, asynchronous operations are common, whether fetching data from a database, interacting with APIs, or performing complex computations. While the async/await approach provides elegant error handling via try...catch, handling errors in the Promise API requires a slightly different strategy.

This guide explores how to manage errors effectively in asynchronous route handlers that use Promises and the .then() and .catch() methods.

The Problem

Consider the following route handler using the Promise-based delay function:


// Handle async processing with Promise using .then()
app.get('/wait', (req, res) => {
  delay(1000)
    .then(response => {
      res.json({
        message: response,
      });
    });
});

      

This code works perfectly if the Promise resolves successfully. However, if the Promise is rejected (e.g., delay(-1)), the browser hangs indefinitely, and you’ll see an UnhandledPromiseRejectionWarning in the console.

Why does this happen? Promises don't automatically throw errors for rejection—they rely on explicit error handling using the .catch() method.

The Solution

To ensure rejected Promises don’t cause the application to hang, chain a .catch() method to the Promise and pass the next argument from the route handler. This sends the error to Express's error-handling middleware.


// Handle async processing with Promise using .then().catch()
app.get('/wait', (req, res, next) => {
  delay(-1)
    .then(response => {
      res.json({
        message: response,
      });
    })
    .catch(next);
});

      

Key points:

Why .catch(next) Works

In Express, the next function is used to pass control to the next middleware. When you call next(err), Express automatically recognizes the argument as an error and routes the request to your error-handling middleware.

Think of next as an emergency hotline. If something goes wrong (an error in this case), you dial the hotline (next(err)) to alert the system and trigger appropriate action.

Best Practices for Promise-Based Error Handling

Following these practices helps build resilient applications that handle unexpected issues gracefully.

What You Learned

By understanding and implementing proper error handling in the Promise API, you ensure your applications are robust, user-friendly, and prepared for the complexities of asynchronous programming.