2

I am currently wondering why the throw in this ES6 native Promise setup is not arriving in the catch block

new Promise(function(resolve,reject){

    reject('bar')

}).then(function resolved(){

    console.log('resolved 1');

}, function rejected(){

    console.log('rejected 1')
    throw new Error();

}).then(function resolved(val){

    console.log('resolved 2');

}, function rejected(){

    console.log('rejected 2');

}).catch(function(err){

    console.log('catch');

});

I am looking for a way to get the control flow to the catch block, but if I use a rejected handler, if I throw an error, the control ends up there, and not in the catch.

In simpler terms, I am looking for a way to end up in the catch block, even if there is a onRejected handler...is there a way to do that?

new Promise(function(resolve,reject){

    throw new Error(); // this goes to onRejected
    reject('bar'); // this goes to onRejected


}).then(function onResolved(){

    console.log('resolved');

}, function onRejected(){

    console.log('rejected')


}).catch(function(err){

    console.log('catch');

});

my goal is to branch separately, based on whether an error is thrown versus whether reject is called. Not sure if it's possible. Perhaps there is a way to call catch explicitly? I'd like to find a way to do this without explicitly throwing a new error in the final onRejected handler if possible.

Here is my goal, with comments:

new Promise(function(resolve,reject){

    if(success){
       resolve('success');   //this goes to next onResolved
    }
    else if(fail){
       reject('fail');      //this goes to next onRejected (or catch if there is no onRejected)
    }
    else {
       throw new Error('Fatal');  //this goes to next catch
    }

});

that's the behavior I am looking for

Alexander Mills
  • 90,741
  • 139
  • 482
  • 817
  • When you "handle" the rejection with a reject handler, the reject is considered "handled" now and the promise state changes to fulfilled unless you either return a rejected promise from the reject handler or you throw from the reject handler. That's the way promise reject handlers are designed. You cannot change that. Throw or return a rejected promise if you want the rejection to NOT be handled and to continue to propagate. There is no way around that fundamental design decision. – jfriend00 Feb 18 '16 at 22:09
  • 1
    You cannot distinguish between "next catch" and "next onrejected" - `.catch(…)` is just sugar for `.then(null, …)` and behaves exactly the same. If you want to branch, you should [actually branch](http://stackoverflow.com/a/27218802/1048572). – Bergi Feb 18 '16 at 22:23

1 Answers1

3

The reason the error is not arriving at .catch() is due to error being handled within onRejected.

To pass error handled within onRejected to chained .catch() throw error again within onRejected

new Promise(function(resolve,reject){

    throw new Error(); // this goes to onRejected
    reject('bar'); // this goes to onRejected


}).then(function onResolved(){

    console.log('resolved');

}, function onRejected(err){

    console.log('rejected')
    throw err

}).catch(function(err){

    console.log(err, 'catch');

});

Edit, Updated

To handle error before onRejected add .catch() before chained .then()

var success = 0,
  fail;

var p = new Promise(function(resolve, reject) {

  if (success) {
    resolve('success'); //this goes to next onResolved
  } else if (fail) {
    reject('fail'); //this goes to next onRejected (or catch if there is no onRejected)
  } else {
    throw new Error('Fatal'); //this goes to next catch
  }

});

p.catch(function(err) {
    console.log("error handled within catch:", err)
})
.then(function(data) {
    // error handled, `p` is now `resolved`
    console.log("resolved", data)
  }, function(err) {
    console.log("rejected", err)
})
guest271314
  • 1
  • 15
  • 104
  • 177
  • yeah, thanks, but actually, I want to avoid that as it stands, because this is for a library and I don't want to require that users throw in onRejected, I want to have some flow go directly to the catch...does that make sense? – Alexander Mills Feb 18 '16 at 20:58
  • _"I want to have some flow go directly to the catch"_ Not certain interpret this correctly ? – guest271314 Feb 18 '16 at 21:00
  • perhaps I can throw in on resolved, instead of on rejected...that would be a trick – Alexander Mills Feb 18 '16 at 21:00
  • basically, I want to branch code --> if the flow ends up in the catch, it means one thing (a more fatal error) then if the flow ends up in on rejected (less fatal error)..that's my current goal – Alexander Mills Feb 18 '16 at 21:01
  • Yes, could use `throw` within `onResolved`. Though, if error is handled in an `onRejected` before `.catch()` , error would not reach subsequent `.catch()` – guest271314 Feb 18 '16 at 21:02
  • What is the purpose of including both `onRejected` and `.catch()` ? Why can error not be handled in `onRejected` ? – guest271314 Feb 18 '16 at 21:04
  • simply because it simplifies the behavior of the library – Alexander Mills Feb 18 '16 at 21:05
  • What is logic on how to distinguish different errors ; what is difference between a _"more fatal error"_ and a _"less fatal error"_? Tried using an `if..else` statement within either `onRejected` or `.catch()` to handle errors differently ? – guest271314 Feb 18 '16 at 21:08
  • I could have the users of my library use a switch statement to distinguish between errors. But there is a difference between a soft error (a reject) and a hard/fatal error that means there is an unexpected error, which I believe belongs in the catch block – Alexander Mills Feb 18 '16 at 21:11
  • I added one more block of code in the question to illustrate – Alexander Mills Feb 18 '16 at 21:11
  • @AlexMills See updated post – guest271314 Feb 18 '16 at 21:17
  • ahhh, that should work, the catch before the next then, good one, let me test it – Alexander Mills Feb 18 '16 at 21:22
  • fml, if we put the catch before the then, what happens is that onResolved gets called, how to prevent onResolved from being called after the catch? I want to branch the logic – Alexander Mills Feb 18 '16 at 21:26
  • _"how to prevent onResolved from being called after the catch?"_ `throw` error , as described at initial stacksnippets – guest271314 Feb 18 '16 at 21:27
  • yes, but then the error will get swallowed, because I don't want another catch after the then... – Alexander Mills Feb 18 '16 at 21:28
  • _"how to prevent onResolved from being called after the catch?"_ What is expected result ? The error was handled , the `Promise` returned from `.catch()` now has a resolved status – guest271314 Feb 18 '16 at 21:29
  • http://openmymind.net/Cancelling-Long-Promise-Chains/ – Alexander Mills Feb 18 '16 at 21:31
  • Not certain what link is attempting to describe ? – guest271314 Feb 18 '16 at 21:33
  • https://blog.codecentric.de/en/2015/03/cancelable-async-operations-promises-javascript/ – Alexander Mills Feb 18 '16 at 21:33
  • the bottom line is that I want to branch using promises, but I can't branch, it always goes to the next handler, no matter what – Alexander Mills Feb 18 '16 at 21:34
  • Again, what is expected result once error is handled ? For both `.then()` or `.catch()` that are possibly chained to do nothing ? – guest271314 Feb 18 '16 at 21:34
  • let me describe my use case - I have a rate limiting library, using redis. either the request exceeds the rate limit or it doesn't exceed the rate limit, or some error is thrown (redis error etc)...I want resolve to represent an OK request, I want reject to represent a request that exceeds the limit, and I want catch to represent an error that gets thrown inside my lib – Alexander Mills Feb 18 '16 at 21:36
  • Are you attempting to re-define `.catch()` ? `Promise` does not process in that manner; although you could try using `unhandledrejection` or `rejectionandled` events in chrome / chromium 49+ ; see http://stackoverflow.com/questions/35398365/js-promises-fulfill-vs-resolve/ – guest271314 Feb 18 '16 at 21:39
  • yeah, it's quite possible that native ES6 promises can't do what I want – Alexander Mills Feb 18 '16 at 21:40
  • The simplest approach would be to use `if..else` statement in either `.catch()` or `onRejected` and `throw` if error should be passed – guest271314 Feb 18 '16 at 21:41
  • yeah, I think you're right – Alexander Mills Feb 18 '16 at 21:44
  • @AlexMills See also http://stackoverflow.com/questions/35042068/why-is-onrejected-not-called-following-promise-all-where-promise-reject-incl – guest271314 Feb 18 '16 at 21:48