Reputation: 18197
I have a big problem with node.js.
For information, i used the version 0.12 because our app is so complexe and large, it's not possible to migrate easilly onto newest version.
And, with that, many functions are callbacks functions.
But, in new part of this projet I want to use Promises to easilly catch errors. And I have a problem with an uncaught exception in the event loop.
This is the test code :
process.on('uncaughtException', function (err) {
console.error('Uncaught Exception');
});
new Promise(function () {
process.nextTick(function () {
var a = null;
a.b;
});
}).catch(function (e) {
console.log('catched by Promise');
});
If I test this code, Systematically I pass onto the uncaughtException
.
It's possible to capture this type of error with promises ?
Thanks
Upvotes: 1
Views: 4037
Reputation: 707318
Promises will catch exceptions for you automatically in two places: 1) in a Promise executor function and 2) in a .then()
or .catch()
handler. In both cases, they catch the exception and turn it into a rejected promise. Here are a couple examples:
// Promise executor
new Promise(function(resolve, reject) {
var a = null;
a.b = 0; // throws an exception
resolve("done");
}).then(function(data) {
console.log(data); // never gets here
}).catch(function(err) {
console.log(err); // shows the above exception
});
// .then() handler
Promise.resolve().then(function(data) {
var a = null;
a.b = 0; // throws an exception
return "hello";
}).then(function(data) {
console.log(data); // never gets here
}).catch(function(err) {
console.log(err); // shows the above exception
});
So, if you promisify all your async operations so all the completion or error handlers are .then()
handlers or .catch()
handlers, then the promise infrastructure will catch exceptions in all those. But, it won't catch exceptions outside these circumstances. If you're using setTimeout()
or any other async operation that has not been wrapped in a promise, then you will have to wrap those callbacks in try/catch yourself. But, it is simple to do. Instead of setTimeout()
a simple function that is promise based can be used:
So, instead of this:
setTimeout(someFunction, 100);
You can use this:
delay(10).then(someFunction).catch(...);
Where the implementation of delay()
is this:
function delay(t) {
return new Promise(function(resolve) {
setTimeout(resolve, t);
});
}
Now, all synchronous exceptions in someFunction()
will be caught for you. If it does its own async operations, then those too have to be converted to use promises.
You can, of course, wrap your own try/catch around other circumstances to catch your own exceptions elsewhere.
You can use something like Bluebird's Promise.promisifyAll()
to make promisified versions of an entire interface. For example, I use it all the time with the fs
module to make promisified versions of the entire fs
interface so I can use promises for all file access functions. You can see more about the reasons to use Bluebird here: Are there still reasons to use promise libraries like Q or BlueBird now that we have ES6 promises?
In your specific example:
new Promise(function () {
process.nextTick(function () {
var a = null;
a.b;
});
}).catch(function (e) {
console.log('catched by Promise');
});
You are throwing an exception in an async callback that is not one of the conditions that promises catch exceptions for you. The main thing I can think of would be this:
// wrapper function to run a function upon nextTick and catch exceptions in it
function nextTick(fn) {
return new Promise(function(resolve, reject) {
process.nextTick(function() {
try {
resolve(fn());
} catch(e) {
reject(e);
}
});
});
}
nextTick(function() {
var a = null;
a.b = 0; // throw exception
}).catch(function(e) {
// catches exception here
});
You could, of course, also just catch the exception yourself and handle it locally, but it is harder to propagate the error back up to a higher level without promises:
process.nextTick(function () {
try {
var a = null;
a.b = 0;
} catch(e) {
// handle exception here
}
});
Upvotes: 5