How to catch uncaught exception in Promise
Is there any way to globally catch all exceptions including Promise exceptions. Example:
window.onerror = function myErrorHandler(errorMsg, url, lineNumber) {
alert("Error occured: " + errorMsg);//or any message
return false;
}
var myClass = function(){
}
var pr = new Promise(function(resolve, react){
var myInstance = new myClass();
myInstance.undefinedFunction(); // this will throw Exception
resolve(myInstance);
});
pr.then(function(result){
console.log(result);
});
// i know right will be this:
// pr.then(function(result){
// console.log(result);
// }).catch(function(e){
// console.log(e);
// });
This script will silently die without error. Nothing in firebug.
My question is if I do a mistake and forgot to catch it is there any way to catch it globally?
Update, native promises now do the following in most browsers:
window.addEventListener("unhandledrejection", function(promiseRejectionEvent) {
// handle error here, for example log
});
We were just discussing this the other day.
Here is how you'd do this with bluebird:
window.onpossiblyunhandledexception = function(){
window.onerror.apply(this, arguments); // call
}
window.onerror = function(err){
console.log(err); // logs all errors
}
With Bluebird it's also possible to use Promise.onPossiblyUnhandledRejection
. The calls for done
are not needed as the library will detect unhandled rejection itself unlike Q (UPDATE 2016 - I now wrote code for Q and it does this).
As for native promises - they will eventually report to either window.onerror or a new handler but the specification process is not yet done - you can follow it here.
Most promise implementations don't currently provide the type of functionality you are referring to, but a number of 3rd-party promise libraries (including Q and bluebird) provide a done()
method that will catch and rethrow any uncaught errors, thus outputting them to the console.
(Edit: see Benjamin Gruenbaum's answer about Bluebird's features for handling uncaught exceptions)
So if you have that, you'd just need to follow the rule of thumb that any promise you use should either be returned or terminated with .done()
:
pr.then(function(result){
console.log(result);
})
.done();
To quote from the Q API reference:
The Golden Rule of
done
vs.then
usage is: eitherreturn
your promise to someone else, or if the chain ends with you, calldone
to terminate it. Terminating withcatch
is not sufficient because thecatch
handler may itself throw an error.
I realize that this still requires a bit of extra work and you can still forget to do this, but it is an improvement over having to .catch()
and explicitly handle every error, especially for the reason pointed out above.
In Node.js, you can use:
process.on('unhandledRejection', (reason, promise) => {
console.error(`Uncaught error in`, promise);
});
If you're writing code that can be executed both in a browser & in a Node.js environment, you could wrap your code in a self-executing function like this :
var isNode = (typeof process !== 'undefined' && typeof process.on !== 'undefined');
(function(on, unhandledRejection) {
// PUT ANY CODE HERE
on(unhandledRejection, function(error, promise) {
console.error(`Uncaught error in`, promise);
});
// PUT ANY CODE HERE
})(
isNode ? process.on.bind(process) : window.addEventListener.bind(window),
isNode ? "unhandledRejection" : "unhandledrejection"
);
What would happen if you use this code :
If you'd run it in a Node.js environment, your handler would be attached to the process object and be executed when you have an uncaught exception in a promise.
If you'd run it in a browser environment, your handler would be attached to the window object and be executed when you have an uncaught exception in a promise and your browser supports the
unhandledrejection
event.If you'd run it in a browser environment without support for the
unhandledrejection
, you will not be able to catch your uncaught exception and yourunhandledrejection
event handler will never be triggered, but you would not get any errors if there's no uncaught exceptions.
If you are using native Promise, it's pretty simple.
You only need to .catch
this reject some where.
ajax(request).catch(function(rejected){
console.log(rejected);
});
If I don't catch it somewhere, the uncaught in promise will keep showing. But If I catch it somewhere...