2

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.

Ville Miekk-oja
  • 18,749
  • 32
  • 70
  • 106
  • 1
    This is exactly why a) no promise-returning function should throw and b) you [should prefer the promise constructor over deferreds](http://stackoverflow.com/q/28687566/1048572) – Bergi Aug 09 '16 at 11:51
  • But how can you guaranteet that a no promise-returning function won't throw? I mean you could be using some external library?But, I think you might be on the right track, you could provide an answer perhaps. – Ville Miekk-oja Aug 09 '16 at 11:56
  • By debugging/eliminating Errors, and by wrapping possibly throwing Code in a try..catch-block and handling the Error; maybe by returning `Q.reject(error)`. – Thomas Aug 09 '16 at 12:08

4 Answers4

2

Q has specific function for success and error, so use:

deferred.reject("error");

intead of throwing an Exception.

Next thing is that someFunction must return promise to be used as You use it:

function someFunction() {

  var deferred = Q.defer();

  try{

  //some Asynchronous code
  deferred.resolve("success");


  }catch(e){

    deferred.reject(e.message);

  }

  return deffered.promise; //return promise to use then
}
Maciej Sikora
  • 19,374
  • 4
  • 49
  • 50
  • Yes I know. But, what if I execute code in the someFunction(), that will throw an error? Then only option would be to wrap the whole someFunction inside try/catch clause, which just feels wrong... Inside the someFunction, I could use some external libraries that might result in an error for example. – Ville Miekk-oja Aug 09 '16 at 11:42
2

Because Promises ain't magic. They don't somehow magically catch Errors. They catch them, because they wrap the calls to the callbacks in try..catch-blocks, to convert Errors into rejected Promises.

If you want an Error to be handled by the Promise-chain, well put the function-call into a promise-chain: Q.resolve().then(someFunction).then(...). Now any synchronous Error occuring in someFunction can be handled in the following then's.

Btw: If you use Q.defer(), and you're not dealing with some callback-style API, you're doing it definitely wrong. Search for the Deferred-antipattern.

Thomas
  • 11,958
  • 1
  • 14
  • 23
1

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");
  });
}
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
0

throwing an error will stop the code from executing (and will close node) unless you catch the error in a try/catch block.

handled errors from requests can be passed to the .catch chain by using deferred.reject(error). code errors and custom thrown errors needs to be handled inside try/catch, which is the right way to handle such errors.

function someFunction() {
  var deferred = Q.defer();
  deferred.reject("Can't bar.");
  // or
  try {
    throw new Error("Can't bar.");
  }
  catch(err) {
    deferred.reject("Can't bar.");
  }

  deferred.resolve("success");
}
Bamieh
  • 10,358
  • 4
  • 31
  • 52