I am using Cujo's great When library to provide a Promises/A+ implementation for my Node project, although this question is not node-specific.
Generally, When's great: it lets me write more maintainable, readable code.
However, when my callbacks fail unexpectedly (accessing a property of a null variable, etc), the exceptions are effectively swallowed by When, as seems to be specified by the Promises/A+ spec. Unfortunately, this means I don't get any feedback about the error (other than the callback stops executing at that point). No error type or message, no line number.
To illustrate:
// hypothetical asynchronous database query
database.query(queryDetails).then(function(result) {
var silly = 3.141592654;
silly(); // TypeError: number is not a function!
process(result); // this code is silently never executed
});
I can think of a handful of (unacceptable) ways to tackle this:
then
call (to dump the reason/exception to the console)console.log('I got here 123')
Am I just doing it wrong? Surely I'm not alone in finding the debuggability of promises-based code poor. Is there an obvious solution I'm missing?
Here is how I detect when a Promise has been rejected on Node but not caught:
if (typeof process === 'object') {
process.on('unhandledRejection', (error, promise) => {
console.error("== Node detected an unhandled rejection! ==");
console.error(error.stack);
});
}
In addition to that, you could use this monkey wrapper to provide long stack traces for Node's ES6 Promises. It produces similar output to Q's longStackSupport
. I would not recommend it for use outside of development code, due to performance concerns. (It's working for me in Node v4.4.1. I have not yet tested it in Chrome or Firefox.)
Update Sep 2016: NodeJS 6.6.0+ and 7.0+ will warn automatically on unhandled rejections. Run node with --trace-warnings
to get reasonable stack traces. Still not as good as what bluebird gives you but a lot better than the situation before.
Ok, so summing up the information from the comments and add some.
.done
method that explicitly declares the chain has ended, this causes uncaught rejections to be thrown. Libraries like When and Q solve the problem this way. For example if your .then
after .query
was a .done
you'd get a long stack trace.As such:
require('when/monitor/console'); // when will now log async rejections used with
// `then` , this is experimental in when.
With bluebird
Promise.longStackTraces(); // Bluebird always logs async rejections but with this
// option it will stitch the asynchronous context stack
// for you in your methods.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With