Ville Miekk-oja Ville Miekk-oja - 3 months ago 8
Javascript Question

Catching errors with Q.deferred

I have a nodeJS project where I wish to use asynchronous functions. Namely, I'm using the Q library.

I have a function called someFunction(), that I wish to return a promise. With the then -function, I can then check whether the promise was resolved or rejected like so:

someFunction()
.then(
function(results) {
console.log("Success!");
},
function (error) {
console.log("An error occurred, and I would wish to log it for example");
}
);


What I intuitively expect with the function above is, that the error function would catch all possible errors. So if some exception is raised inside the someFunction, I can rest assured, that the error function will be run (the second function after 'then'). But it seems this is not the case.

For example, let's say the someFunction would be defined as so:

function someFunction() {
var deferred = Q.defer();
throw new Error("Can't bar.");

deferred.resolve("success");
}


Now if I call the function someFunction() like done in the upper code block, it won't run the error function. Why is that? Isn't the partial point of the promise Q.deferred to catch errors? Why should I manually reject every error that happens? I know I could set the whole content of someFunction to try/catch clause, and then reject the deferred, but that feels so wrong! There must be a better way, and I know for sure some of you stackoverflowers know it!

With this information, I began to think about where the deferred.reject and deferred.resolve is even meant to be used? Is it even meant to catch exceptions? Should I really just go through all the error cases manually, and call the deferred.reject on them? I'm interested to hear how this should be handled professionally.

Answer

it won't run the error function. Why is that?

Because you synchronously threw an exception, instead of returning a promise. Which you never should.

Isn't the partial point of the promise Q.deferred to catch errors?

No. then and catch implicitly catch exceptions in their callbacks, defferreds don't - they're just a (deprecated) API to create promises.

Why should I manually reject every error that happens?

Because asynchronous errors are expected to be passed to callbacks anyway, instead of being thrown.

I know I could set the whole content of someFunction to try/catch clause, and then reject the deferred, but that feels so wrong! There must be a better way!

There is: the Q.Promise constructor, the standard (ES6) promise creation API. It has the benefit of being able to catch synchronous exceptions from the executor function:

function someFunction() {
  return new Q.Promise(function(resolve) {
    throw new Error("Can't bar.");
    resolve("success");
  });
}
Comments