简体   繁体   English

用errorCallback打破Promise“then”链

[英]Break out of a Promise “then” chain with errorCallback

-- 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 : 如果在Auth.signup()中出现问题,这就是显示:

  • errCall, loginSucc errCall,loginSucc

if i do a $q.reject() in the errCall this is what happens : 如果我在errCall中执行$ q.reject(),则会发生以下情况:

  • errCall, loginErr errCall,loginErr

and this is what i want : 这就是我想要的:

  • errCall... finish, stop here errCall ...完成,停在这里

Now, the problem is, it goes in errCall when signup goes wrong, that's good, but then it enters loginSucc... 现在,问题是,当注册出错时,它会进入errCall,这很好,但随后它进入loginSucc ......

I want to break out of the then chain when any errorCallback (which is errCall or loginErr here) is encountered. 当遇到任何errorCallback(这是errCall或loginErr)时,我想突破当时的链。

-- 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 我的观点是,如果我有很多“然后”链接,我不想只有一个错误处理程序

errCall function needs tor return a promise, and that promise needs to be rejected for loginErr to be fired. errCall函数需要返回一个promise,并且需要拒绝该promise以errCall loginErr。

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

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


}

Alternatively try .catch : 或者尝试.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
 });

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. 在你的errCall()函数中。

EDIT: As OP remarked by calling $q.reject the code will enter the loginErr function. 编辑:正如OP通过调用$q.reject ,代码将进入loginErr函数。 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: 您可以在这两个SO问题中阅读更多内容:

  1. Break promise chain 打破承诺链
  2. Break Out of then promises in Angularjs 突破Angularjs的承诺

This also is a helpful read : Flattening Promise Chains 这也是一个有用的解读: 扁平化承诺链

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() . 只是不要传递任何errCallloginErr then在promise链的末尾使用catch() ,它将在第一个错误中被中断,它将被传递给catch() If you want explicitly process error of Auth.signup() then your errCall should look like this: 如果你想显式处理Auth.signup()错误,那么你的errCall应该如下所示:

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() : 您最好的选择是返回一个永远不会从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. 当然,在评估第一个承诺期间发生错误时,会调用loginSucc函数。 However, that can be fixed by rejecting once again in errCall as others have already pointed out. 但是,正如其他人已经指出的那样,可以通过在errCall再次拒绝来解决这个问题。 But you should not try to avoid the execution of loginErr , otherwise something is conceptually wrong with your code. 但是你不应该试图避免执行loginErr ,否则你的代码在概念上是错误的。

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. 合同是promise有一个then()方法,它将两个回调作为参数,一个用于成功,一个用于失败。 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. 合同还包括成功评估promise并在所有其他情况下调用错误/失败回调时调用成功回调。 If you intend to never call either of those, don't use a promise! 如果您打算永远不打电话给其中任何一个,请不要使用承诺!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM