How to create a global Promise Rejection Handler in JavaScript?


Promise rejection handlers are a powerful tool in JavaScript for handling errors that occur in asynchronous code. In this article, we will learn how to build a global promise rejection handler in JavaScript and how it might assist your application manage errors. You can detect unhandled promise rejections using the global unhandledrejection event and take the necessary action, like logging the problem to an error tracking service or showing the user a notice.

A more understandable and simpler syntax for handling promise rejection is provided by error handling with async-await, but it necessitates that you wrap each async function in a try-catch block. Async-await with a global promise rejection handler combined can give your application a strong and reliable error handling system.

What is Promise Rejections?

Promises in JavaScript are a way to handle asynchronous code, such as fetching data from a server or waiting for a user's input. A promise is an object that represents a value that may not yet be available. Promises have three states −

Pending − The initial state, neither fulfilled nor rejected.

Fulfilled − Meaning that the operation completed successfully.

Rejected − Meaning that the operation failed.

When a promise is rejected, it will trigger a rejection handler if one is attached to the promise. This allows you to handle the error and take appropriate action. However, if there is no rejection handler attached to the promise, the error will go unnoticed and can lead to bugs in your application.

Creating a Global Promise Rejection Handler

JavaScript provides a global unhandledrejection event that can be used to catch unhandled promise rejections. The unhandledrejection event is triggered when a promise is rejected and no rejection handler is attached to the promise.

Example

<html>
<body>
   <div id="error-message"></div>
   <script>
      window.addEventListener("unhandledrejection", event => {
         document.getElementById("error-message").innerHTML = event.reason;
      });
      
      // Create a new promise that intentionally rejects
      const myPromise = new Promise((resolve, reject) => {
         reject(new Error("Intentional error"));
      });

      // Use the promise
      myPromise.catch(error => {
         document.getElementById("error-message").innerHTML = error.message;
      });
   
      // Function to reject the promise when the button is clicked
      function rejectPromise() {
         myPromise.catch(() => {});
      }
   </script>
</body>
</html>

This code attaches an event listener to the global unhandled rejection event, which will be triggered when a promise is rejected and no rejection handler is attached to the promise. The event object passed to the event listener contains a reason property that holds the rejection reason.

The rejected promise can likewise be handled more centrally using this event. For instance, you can use it to display a message to the user, log the problem to an error tracking service, or do other necessary actions. When dealing with large applications, where it might be challenging to keep track of all the promises and associated rejection handlers, this can be extremely helpful.

window.addEventListener("unhandledrejection", event => {
    logErrorToService(event.reason);
    displayErrorMessage(event.reason);
});

Example

We can use the above snippet in our code as follows −

<html>
<body>
   <div id="error-log"></div>
   <div id="error-message"></div> 
   <script>
      window.addEventListener("unhandledrejection", event => {
         logErrorToService(event.reason);
         displayErrorMessage(event.reason);
      });
      function logErrorToService(error) {
         
         // Code to log error to a service
         var errorLog = document.getElementById("error-log");
         errorLog.innerHTML = error;
      }
      function displayErrorMessage(error) {
         
         // Code to display error message on screen
         var errorMessage = document.getElementById("error-message");
         errorMessage.innerHTML = error;
      }
      
      // Create a new promise that intentionally rejects
      const myPromise = new Promise((resolve, reject) => {
         reject(new Error("Intentional error"));
      });
      
      // Use the promise and handle the rejection
      myPromise.catch(error => {
         displayErrorMessage(error.message);
      });
   </script>
</body>
</html>

The unhandledrejection event is caught in this example, and the error is sent to two different functions: one that reports the error to an error tracking service, and another that shows the user an error message.

You should be cautious while implementing this and take care not to interfere with any other error handling techniques that are already in place in your application because this global event listener will catch all unhandled promise rejections on the page.

Error Handling with Async-Await

Async-await is a more readable and cleaner syntax for working with promises. You can handle errors using a standard try-catch block when using async-await.

async function fetchData() {
     try {
         const response = await
        fetch('https://jsonplaceholder.typicode.com/posts/1');
         const data = await response.json();
         console.log(data);
     } catch (error) {
         console.error(error);
     }
}

Example

We can use the above snippet in our code as follows −

<html>
<body>
   <script>
      async function fetchData() {
         try {
            const response = await
            fetch('https://jsonplaceholder.typicode.com/posts/1');
            const data = await response.json();
            var dataDisplay = document.getElementById("data-display");
            dataDisplay.innerHTML = JSON.stringify(data);
         } catch (error) {
            var errorDisplay = document.getElementById("error-display");
            errorDisplay.innerHTML = error;
         }
      }
   </script>
   <button onclick="fetchData()">Fetch Data</button>
   <div id="data-display"></div>
   <div id="error-display"></div>
</body>
</html>

Using the await keyword, the asynchronous function fetchData in this example waits for the promise returned by the fetch method to resolve. The catch block will catch any errors that happen in the try block and log them to the console.

While more accessible and understandable, this approach to error handling necessitates that you wrap each async function in a try-catch block. When working with large systems that have a lot of asynchronous code, this can get laborious and error-prone.

However, combining the use of async-await with a global promise rejection handler can provide a powerful and robust error handling mechanism. By using a global promise rejection handler to catch unhandled promise rejections, you can ensure that all errors in your application are handled, even if you forget to wrap an async function with a try-catch block.

It's critical to remember that effective error handling is essential for delivering a better user experience and for swiftly fixing faults. A valuable tool that can assist you in doing this is a global promise rejection handler, but it should be used with caution and in conjunction with other error handling systems.

Updated on: 02-Mar-2023

575 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements