2016-04-12

Tracking unhandled rejected Promises

In Promise-based asynchronous code, rejections are used for error handling. One risk is that rejections may get lost, leading to silent failures. For example:

    function main() {
        asyncFunc()
        .then(···)
        .then(() => console.log('Done!'));
    }

If asyncFunc() rejects the Promise it returns then that rejection will never be handled anywhere.

Let’s look at how you can track unhandled rejections in browsers and in Node.js.

Unhandled rejections in browsers

Some browsers (only Chrome at the moment) report unhandled rejections.

unhandledrejection

Before a rejection is reported, an event is dispatched that you can listen to:

    window.addEventListener('unhandledrejection', event => ···);

The event is an instance of PromiseRejectionEvent whose two most important properties are:

  • promise: the Promise that was rejected
  • reason: the value with which the Promise was rejected

The following example demonstrates how this event works:

    window.addEventListener('unhandledrejection', event => {
        // Prevent error output on the console:
        event.preventDefault();
        console.log('Reason: ' + event.reason);
    });
    
    function foo() {
        Promise.reject('abc');
    }
    foo();

The output of this code is:

    Reason: abc

rejectionhandled

If a rejection is initially unhandled, but taken care of later then rejectionhandled is dispatched. You listen to it as follows:

    window.addEventListener('rejectionhandled', event => ···);

event is also an instance of PromiseRejectionEvent.

The following code demonstrates rejectionhandled:

    window.addEventListener('unhandledrejection', event => {
        // Prevent error output on the console:
        event.preventDefault();
        console.log('Reason: ' + event.reason);
    });
    window.addEventListener('rejectionhandled', event => {
        console.log('REJECTIONHANDLED');
    });
    
    
    function foo() {
        return Promise.reject('abc');
    }
    var r = foo();
    setTimeout(() => {
        r.catch(e => {});
    }, 0);

This code outputs:

    Reason: abc
    REJECTIONHANDLED

Further reading

The Chrome Platform Status site links to a “Promise Rejection Events Sample” that contains an explanation and code.

Unhandled rejections in Node.js

Node.js does not report unhandled rejections, but it emits events for them. You can register an event listener like this:

    process.on('unhandledRejection', (reason, promise) => ···);

The following code demonstrates how the event works:

    process.on('unhandledRejection', (reason) => {
        console.log('Reason: ' + reason);
    });
    function foo() {
        Promise.reject('abc');
    }
    foo();

Further reading

The Node.js documentation has more information on the Event unhandledRejection.

No comments: