Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent ES6 promises from swallowing errors (without using .catch)

I do not want to type .catch for every promise I use. Without doing this errors caused by promises are supremely unhelpful.

Using an entire library like bluebird purely for this purpose makes me uncomfortable.

like image 320
Mentor Avatar asked Jan 10 '17 12:01

Mentor


People also ask

How do you prevent promises swallowing errors in JavaScript?

Add a handler to your process for unhandled rejections. You can handle them once like that instead of copy-pasting . catch statements all the time. catch() should be used to handle errors, not just report them.

What is the problem with promises in JavaScript?

Promises co-mingle rejected promises and unintended runtime exceptions. Apart from how the API is structured - promises have another major flaw: they treat unintentional native runtime exceptions and intentional rejected promises - which are two drastically different intentions - in the same "path".

Are promises blocking JavaScript?

When using Javascript promises, does the event loop get blocked? No. Promises are only an event notification system. They aren't an operation themselves.

What are the states of promises in ES6?

A Promise is in one of these states: pending: initial state, neither fulfilled nor rejected. fulfilled: meaning that the operation was completed successfully. rejected: meaning that the operation failed.


2 Answers

For error tracking during development, V8 (recent Node.js and Chrome versions) already has got unhandledRejection (Node.js) and unhandledrejection (Chrome) event listener by default, which results in UnhandledPromiseRejectionWarning warning in Node.js and Uncaught (in promise) error in Chrome.

Deprecation warning in Node 7 states that this will be changed in future Node.js versions:

Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Error handling in promises is not optional and should be treated on par with try...catch. Every promise that has a chance to be rejected should be chained with catch. And in the case of async...await or co, .catch is identical to try...catch.

If the error is supposed to be ignored, it has to be explicitly caught. If error handling needs to be consistent across the app and comply to log levels, this may be provided by design. E.g. with conventional debug package:

const debug = require('debug');

function catchFn(err, ns = 'myapp:caughtPromises') {
    debug(ns)(err);
}

function catchPromise(promise, ns) {
    promise.catch(err => catchFn(err, ns));
    return promise;
}

...

try {
  await promise;
} catch (err) {
  catchFn(err);
}

// or
catchPromise(promise);

// or
promise.catch(catchFn);

catchFn can be extended to use third-party logging service as well.

like image 51
Estus Flask Avatar answered Oct 04 '22 21:10

Estus Flask


Add a handler to your process for unhandled rejections. You can handle them once like that instead of copy-pasting .catch statements all the time.

process.on( 'unhandledRejection', ( error, promise ) => {
    console.log( 'UPR: ' + promise + ' with ' + error )
    console.log( error.stack )
} )
like image 40
Mentor Avatar answered Oct 04 '22 20:10

Mentor