最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Break out of a Promise "then" chain with errorCallback - Stack Overflow

programmeradmin0浏览0评论

-- EDIT --

I encountered a weird thing recently about promises, but I guess it's maybe because it's against the philosophy of promises.

Considering the following code :

// Assuming Auth is just a simple lib doing http requests with promises
Auth.signup()
 .then(succCall, errCall)
 .then(loginSucc, loginErr)

// My callbacks here
function succCall (){
 // OK, send second promise
 console.log('succCall');
 return Auth.login();
}

function errCall(){
 // I do some things here and now
 // I want to break out from here
 console.log('errCall');
}

function loginSucc(){
 // This is the callback of the login method when it went OK
 // I want to enter here ONLY if with go through the succCall
 console.log('loginSucc');
}

function loginErr(){
 // This is the callback of the login method when it went not ok
 // I want to enter here ONLY if with go through the succCall
 console.log('loginErr');
}

Here if something goes wrong in Auth.signup(), this is what show :

  • errCall, loginSucc

if i do a $q.reject() in the errCall this is what happens :

  • errCall, loginErr

and this is what i want :

  • errCall... finish, stop here

Now, the problem is, it goes in errCall when signup goes wrong, that's good, but then it enters loginSucc...

I want to break out of the then chain when any errorCallback (which is errCall or loginErr here) is encountered.

-- EDIT --

I think i was misunderstood by some mean, i want to totally break the chain without check in any other "then" if something went wrong.

As if i was saying : if first then is wrong stop here, if first then ok continue, if second "then" ok continue, if third "then" wrong, stop

// Just like if i did the following but by chainning "then" methods
// My callbacks here
function succCall (){
 // OK, send second promise
 return Auth.login().then(loginSucc, loginErr);
}

My point is, i don't want only one error handler if i have many "then" chained

-- EDIT --

I encountered a weird thing recently about promises, but I guess it's maybe because it's against the philosophy of promises.

Considering the following code :

// Assuming Auth is just a simple lib doing http requests with promises
Auth.signup()
 .then(succCall, errCall)
 .then(loginSucc, loginErr)

// My callbacks here
function succCall (){
 // OK, send second promise
 console.log('succCall');
 return Auth.login();
}

function errCall(){
 // I do some things here and now
 // I want to break out from here
 console.log('errCall');
}

function loginSucc(){
 // This is the callback of the login method when it went OK
 // I want to enter here ONLY if with go through the succCall
 console.log('loginSucc');
}

function loginErr(){
 // This is the callback of the login method when it went not ok
 // I want to enter here ONLY if with go through the succCall
 console.log('loginErr');
}

Here if something goes wrong in Auth.signup(), this is what show :

  • errCall, loginSucc

if i do a $q.reject() in the errCall this is what happens :

  • errCall, loginErr

and this is what i want :

  • errCall... finish, stop here

Now, the problem is, it goes in errCall when signup goes wrong, that's good, but then it enters loginSucc...

I want to break out of the then chain when any errorCallback (which is errCall or loginErr here) is encountered.

-- EDIT --

I think i was misunderstood by some mean, i want to totally break the chain without check in any other "then" if something went wrong.

As if i was saying : if first then is wrong stop here, if first then ok continue, if second "then" ok continue, if third "then" wrong, stop

// Just like if i did the following but by chainning "then" methods
// My callbacks here
function succCall (){
 // OK, send second promise
 return Auth.login().then(loginSucc, loginErr);
}

My point is, i don't want only one error handler if i have many "then" chained

Share Improve this question edited Dec 21, 2015 at 17:58 darkylmnx asked Dec 21, 2015 at 15:38 darkylmnxdarkylmnx 2,0915 gold badges24 silver badges39 bronze badges 8
  • I think to break the chain you have to reject the promise inside the errCall function. – koox00 Commented Dec 21, 2015 at 15:47
  • @koox00 nope a reject just enters the next error, so loginErr here, and this is what i don't want – darkylmnx Commented Dec 21, 2015 at 16:29
  • @SoluableNonagon has the right answer - use catch and skip your errCall and loginErr functions, and place their logic within the catch. You'll have to look at the error that the catch callback caught but it is the one way to acplish what you want. – Adam Jenkins Commented Dec 21, 2015 at 17:01
  • the question was not to find an alternative, because what you are telling here is an alternative, this is not something that break's out from the chain. I know this method but it's not the one i want, but thanks anyway – darkylmnx Commented Dec 21, 2015 at 17:05
  • can you try to break it down in 2 parts? Auth.signup() .then(succCall, errCall) , succCall.then(loginSucc, loginErr), something like that – koox00 Commented Dec 21, 2015 at 17:37
 |  Show 3 more ments

4 Answers 4

Reset to default 2

What is effectively happening is this:

    try {
        try {
            var a = succCall();
        } catch(e1) {
            a = errCall(e1);
        }
        var b = loginSucc(a);
    } catch(e2) {
        b = loginErr(e2);
    }

You can break out of the chain by calling

return $q.reject('Reason Err was called');

in your errCall() function.

EDIT: As OP remarked by calling $q.reject the code will enter the loginErr function. Alternatively you can modify your code like this:

Auth.signup()
.then(function(a) {
    succCall()
    return loginSucc(a).then(null, loginErr);
}, errCall)

You can read more in these two SO question:

  1. Break promise chain
  2. Break Out of then promises in Angularjs

This also is a helpful read : Flattening Promise Chains

errCall function needs tor return a promise, and that promise needs to be rejected for loginErr to be fired.

function errCall(){
   // i do some things here and now

   return $q(function(resolve, reject) {
        // auto reject
        reject();
   });


}

Alternatively try .catch:

Auth.signup()
 .then(succCall)
 .then(loginSucc)
 .catch(function(err){
      // caught error, problem is you won't know which function errored out, so you'll need to look at the error response
 });

Just don't pass any errCall or loginErr to then and use catch() in the end of the promise chain and it will be interrupted on first error, which will be passed to catch(). If you want explicitly process error of Auth.signup() then your errCall should look like this:

function (err) {
  if(isFatal(err)) {
    return Promise.reject(new Error('Fatal!')); //`catch()` handler will be called with `new Error('Fatal!')`
  } else {
    return 'something'; //next `then()` handler will be called with 'something'
  }
}

Your best option is to return a promise that is never resolved from errCall():

function errCall() {
     console.log('errCall');
     return $q.defer().promise;
}

But you are right, what you are trying to do is "against the philosophy of promises".

Why you shouldn't do it

It is of course a problem that your loginSucc function is called when an error occurs during evaluation of the first promise. However, that can be fixed by rejecting once again in errCall as others have already pointed out. But you should not try to avoid the execution of loginErr, otherwise something is conceptually wrong with your code.

The evaluation of the expression

Auth.signup().then(succCall, errCall)

yields another promise. The contract is that a promise has a then() method taking two callbacks as parameters, one for success and one for failure. The contract is also that the success callback is called when the promise is evaluated successfully and that the error/failure callback is called in all other cases. If you intend to never call either of those, don't use a promise!

发布评论

评论列表(0)

  1. 暂无评论