How to catch uncaught exception in Promise

JavascriptExceptionPromise

Javascript Problem Overview


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?

Javascript Solutions


Solution 1 - Javascript

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.

Solution 2 - Javascript

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: either return your promise to someone else, or if the chain ends with you, call done to terminate it. Terminating with catch is not sufficient because the catch 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.

Solution 3 - Javascript

In Node.js, you can use:

process.on('unhandledRejection', (reason, promise) => {
  console.error(`Uncaught error in`, promise);
});

Solution 4 - Javascript

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 your unhandledrejection event handler will never be triggered, but you would not get any errors if there's no uncaught exceptions.

Solution 5 - Javascript

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...

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJohnView Question on Stackoverflow
Solution 1 - JavascriptBenjamin GruenbaumView Answer on Stackoverflow
Solution 2 - JavascriptJLRisheView Answer on Stackoverflow
Solution 3 - JavascriptJussiRView Answer on Stackoverflow
Solution 4 - JavascriptJohn SlegersView Answer on Stackoverflow
Solution 5 - JavascriptredyyuView Answer on Stackoverflow