3

Background

This question suggests that using throw inside a promise function is effectively identical to calling the reject callback.

e.g. These are equivalent:

new Promise(function(resolve, reject) {
  throw new Error("sadface"); // Using throw
}).catch(function(e) {
  // ... handle error
});
new Promise(function(resolve, reject) {
  reject(new Error("sadface")); // Using reject
}).catch(function(e) {
  // ... handle error
});

Question

Obviously, if there's async code involved (such as an database or HTTP request), you can't use throw, since the stack has changed.

As a "best practice", should I then always use reject inside a promise to keep things consistent? Or should throw still be used under certain circumstances?

Community
  • 1
  • 1
aaaidan
  • 7,093
  • 8
  • 66
  • 102

1 Answers1

3

Obviously, if there's async code involved (such as an database or HTTP request), you can't use throw, since the stack has changed.

That's half the point of promises. Promises are throw safe, they let you use sync facilities like return and throw in asynchronous code.

Synchronous:

try {
   return fn(); 
} catch (e) {
   // handle error
   return recover(e);
}

Promises:

fn().catch(recover);

Or more verbosely:

Promise.resolve().then(function() {
    return fn();
}).catch(function(e) { 
    return recover(e);
});
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
  • So, you're saying I can throw inside a setTimeout inside of a promise? – aaaidan Jan 07 '16 at 23:22
  • 1
    @aaaidan no, you can [convert it to a promise returning function](http://stackoverflow.com/questions/22519784/how-do-i-convert-an-existing-callback-api-to-promises) and then throw inside that - promise code is effectively wrapped in a `try/catch` that converts `throw`s to rejections. – Benjamin Gruenbaum Jan 07 '16 at 23:23
  • Right, so I guess my question is more broadly about whether you should use `resolve/reject` as a matter of course (instead of `return/throw`), or whether it's sometimes good practice to `return/throw`, to clarify intent, say. Does that make any sense? – aaaidan Jan 07 '16 at 23:35
  • @aaaidan prefer `throw` to `return` if it is possible, when you `return` a rejected promise it's effectively like doing `function fn(err){ throw err}; return fn(Error);` which is not as nice as `throw err` :D – Benjamin Gruenbaum Jan 08 '16 at 00:18
  • This is where "best practice" gets tough, since I'd have suggested the opposite :) Returning a rejection wouldn't cause an abrupt completion in JS, so I'd expect it to be faster, and then you don't mix error-handling paradigms. – loganfsmyth Jan 08 '16 at 00:37
  • @BenjaminGruenbaum You mean "prefer throw to _reject_" ? – aaaidan Jan 08 '16 at 00:39
  • @loganfsmyth That's the sort of info I'm interested in an answer... ;) – aaaidan Jan 08 '16 at 00:39
  • @BenjaminGruenbaum In `new Promise`, I'd prefer `reject(new Error())` over `throw new Error()`. In `.then` I'd prefer `return Promise.reject(new Error())` over `throw new Error()`. My point is mostly that this seems kind of subjective. Do whatever you like best :) – loganfsmyth Jan 08 '16 at 01:12