Here's a quick summary of everything we released in Q1 2024.

How to Handle an Unhandled Promise Rejection in JavaScript

The states of JavaScript promises can be pending, fulfilled, or rejected. Let's take a look at what you should do when there is an "unhandled promise rejection".
Joel Olawanle

Joel Olawanle

Feb 07, 2023
unhandled promise rejection

A Promise is a special type of JavaScript object that returns a value you expect to see in the future but do not currently see. It is similar to making a promise in real life, where you promise to do something in the future. A promise always has two outcomes: you either do it by keeping your Promise or you do not.

JavaScript promises are complex but straightforward to grasp. A promise object has two properties: state and result. The state can be pending, fulfilled, or rejected; the result can be undefined or the value of the fulfilled or rejected state.

state and result

  • Pending: This is the initial state of the Promise when it is being processed. This is the initial state before the Promise succeeds or fails and has a result of undefined.
  • Fulfilled: This is the completed and successful state of a Promise. It is also known as the fulfilled state and returns the result ( the resolve value).
  • Rejected: The rejected state, like the resolved or fulfilled states, indicates a failed Promise. The rejected state has a result of the specified reject value.

In clear terms, the promise state is initially pending with a result of undefined; when the Promise's condition is true, the state is fulfilled and has a result with the value of resolve(value); otherwise, when the condition fails, it has an error value of reject (error).

resolve and reject

For example, the code block below is a Promise that checks a condition. If the condition is true it resolves otherwise, it rejects:

const myPromise = new Promise((resolve, reject) => {
let cms = "Hygraph";
if (cms === "Hygraph") {
resolve("Success: The promise has successfully resolved!");
} else {
reject("Failure: The promise has failed!");
}
});

#How to Handle a Promise in JavaScript

A Promise uses two major handler methods: .then() and .catch() to consume and handle when a promise resolve's or reject's. The .then() handler method is called on the Promise object and used to handle the Promise resolve majorly.

The .then() method can take in two functions as parameters in which the first always handles resolve while the second can handle rejection (though not commonly used).

myPromise.then(
(result) => {
console.log(result); // Prints "Success: The promise has successfully resolved!"
},
(error) => {
console.log(error); // Never executes because the Promise is resolved
}
);

The .catch() handler method is specifically used to handle errors (rejections) from promises, and we will explore this handler method in this article because it can be used to handle unhandled promise rejection.

#Unhandled Promise Rejections in JavaScript

Unhandled promise rejections imply that when a promise is rejected, it is not handled. In other words, it is rejected because nothing is dealing with the rejection. Many things can get a promise rejected, such as a network failure or a slow network. When an error arises within a promise, it gets rejected and calls the reject reject() function.

When a promise is rejected, it immediately looks for a rejection handler. If it finds one, that means the Promise rejection is handled and will call the function with the error, but otherwise, it throws a general unhandled promise rejection warning error “uncaught (in promise) …”.

type error failed to fetch

#How to Handle Unhandled Promise Rejection

To handle a promise rejection, you will use the .catch() handler method or add a second function to the .then() handler method.

// Using .catch() handler
myPromise
.then((result) => {
console.log(result);
})
.catch((error) => {
console.log(error);
});
// using .then() handler's second parameter
myPromise.then(
(result) => {
console.log(result);
},
(error) => {
console.log(error);
}
);

In this case, when the promise condition fails, and the rejection is triggered, then it is no longer uncaught, rather it will display the reject error message as seen below:

const myPromise = new Promise((resolve, reject) => {
let cms = "Hygraph";
if (cms === "Sanity") {
resolve("Success: The promise has successfully resolved!");
} else {
reject("Failure: The promise has failed!");
}
});
myPromise
.then((message) => {
console.log(message);
})
.catch((error) => {
console.log(error);
});

This will return "Failure: The promise has failed!" because that is the reject() function’s message (meaning the error message declared in the Promise).

Let’s now explore a real-life example using the FetchAPI. The FetchAPI is a built-in JavaScript method for retrieving resources and interacting with your backend server or an API endpoint. The FetchAPI returns a promise meaning you can use the then() and catch() handler methods.

Let’s retrieve data by sending a GraphQL request with Fetch API to the Cocktails Hygraph content repository which holds some cocktails and some information about each cocktail:

fetch("https://api-us-east-1.hygraph.com/v2/cl4ji8xe34tjp01yrexjifxnw/master", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
query: `
query {
cocktails {
category
info
ingredients
instructions
name
}
}
`
})
})
.then((response) => response.json())
.then((data) => console.log(data));

In the above example, rejection is not handled. In a Fetch API request, the Promise only rejects when a network error is encountered (usually when there's a permissions issue or similar). To avoid having an unhandled promise rejection when there is a network issue or any other error that triggers the reject() function, then you can either use the .catch() handler or introduce a second function parameter to the .then() promise handler:

fetch("https://api-us-east-1.hygraph.com/v2/cl4ji8xe34tjp01yrexjifxnw/master", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
query: `
query {
cocktails {
category
info
ingredients
instructions
name
}
}
`
})
})
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => console.log(error));

At this point, when an error occurs, the error will display instead of having an “uncaught (in Promise) … “ error.

type error failed to fetch

You can also decide to handle this error in a better way and display an error message on the user screen so the user is not left guessing what is wrong:

fetch("https://api-us-east-1.hygraph.com/v2/cl4ji8xe34tjp01yrexjifxnw/master", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
query: `
query {
cocktails {
category
info
ingredients
instructions
name
}
}
`
})
})
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => {
console.log(error);
container.innerHTML = `<p>Something went wrong. Error message: ${error.message}</p>`;
});

The .catch() hander method gives you access to the error object, which holds the message you can display on your webpage for your users to understand the error. This is a proper way to handle errors and applies to promise rejections.

#Wrapping up

In this article, you have learned how to handle an unhandled promise rejection in JavaScript using the .catch() handler method or the second function parameter of the .then() handler method.

Feel free to customize and handle rejections of promises however you'd like, but always make sure to handle rejections of promises when working with promises since your web application may experience a problem at any time.

Blog Author

Joel Olawanle

Joel Olawanle

Joel Olawanle is a Frontend Engineer and Technical writer based in Nigeria who is interested in making the web accessible to everyone by always looking for ways to give back to the tech community. He has a love for community building and open source.

Share with others

Sign up for our newsletter!

Be the first to know about releases and industry news and insights.