Recently I was looking into monitoring static websites and it got me thinking about global error handling. Thereâs a good chance that youâve come across the onerror
global handler thatâs triggered when an error happens and thereâs no try
/catch
around it. But how does this work when working with Promises?
Promise Error Handling
Letâs take this example:
function getJson() {
return fetch('https://url/json')
.then(res => res.json());
}
// or using async/await
function async getJsonAsync() {
const res = await fetch('https://url/json');
const json = await res.json();
return json;
}
There are two errors that could happen here, the first is a network failure and the other is the response isnât valid JSON (side note, fetch
doesnât return an error on a 404 or 500 respose), but weâre not doing anything to handle those errors so weâd need to rewrite it like so:
function getJson() {
return fetch('https://url/json')
.then(res => res.json())
.catch(err => console.log(err));
}
// or using async/await
function async getJsonAsync() {
try {
const res = await fetch('https://url/json');
const json = await res.json();
return json;
} catch (e) {
console.error(e);
}
}
Now we are handling the rejection and our application is all the happier for it.
Handling the Unhandled
In an ideal world, youâre handling all errors that an application may have, but in reality thatâs not the case, there will be errors that were not planned for, which is why we have onerror
. But, onerror
is for handling errors that didnât occur within a Promise, for that we need to look elsewhere.
Promises donât error per se, they reject (which can represent an error or just being unsuccessful), and that rejection may be unhandled which will result in the unhandledrejection
event being triggered.
onunhandledrejection
can be assigned directly off window
like so:
window.onunhandledrejection = function (error) {
console.error(`Promise failed: ${error.reason}`);
};
This is similar to onerror
, but it doesnât have quite as much information provided. All you receive in this event handler is the Promise that failed and the âreasonâ provided to the rejection. This does mean that you donât get some useful information like source file or line number, but thatâs a trade-off because itâs come from an async operation.
You can also call preventDefault
on the error object which will prevent writing to console.error
, which can be useful if you want to avoid leaking information to the debug console.
Handling the Handled
While you can capture unhandled rejections you can also capture handled rejections using the rejectionhandled
event. While I find it annoying that itâs an inconsistent name (Rejection Handled to go along with Unhandled Rejection, why arenât they consistent with where the word Rejection is!) this event handler works the same as the other one but will be triggered when a catch
handled is provided.
This handler is useful if youâre doing a monitoring platform you might want to log all rejections, handled or not.
Conclusion
If youâre building an application you should always look to include global error handling. Itâs very common to handle onerror
but itâs quite easy to forget about global error handling for Promises and thatâs easy to do with onunhandledrejection
.
Top comments (4)
Please, please, please don't do this. This to me is exactly as bad as putting your entire application in a
try, catch
. You'll miss important errors and it'll make debugging a hell. Let your application crash, catch it with a good error reporting tool, and fix it. This is why we run betas and test often.You're right, you should have proper error handling as close to where you expect an error to occur and use a monitoring tool (which I blogged about recently) to capture unhandled errors.
The code illustrated in this post is just what these tools do, they attach to the global events like
onunhandledrejection
andonerror
.The point of this post is to show you how those work so you have a better understanding of just what is happening in the libraries you bring into a project.
Yes, you shouldn't capture a global event and just
console.error
it, you should do something constructive with it, but the code is for illustrative purposes. đI almost missed that great article because i thought it wont answer the question made in title :-)
PS. It helps to have error tracking setup (ie. sentry, raygun) to also get notified about some obscure os/browser combinations that fail sometimes.
So, did I answer the question đ