违背承诺”;那么“;带有错误的链回调

Break out of a Promise "then" chain with errorCallback

本文关键字:有错误 回调 承诺 那么 违背      更新时间:2023-09-26

--编辑--

我最近遇到了一件关于承诺的奇怪事情,但我想这可能是因为它违背了承诺的哲学。

考虑以下代码:

// 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');
}

在这里,如果Auth.signup()出现问题,这就是显示的内容:

  • errCall,loginSucc

如果我在errCall中执行$q.request(),则会发生以下情况:

  • errCall,loginErr

这就是我想要的:

  • errCall。。。完成,在这里停下来

现在,问题是,当注册出错时,它会进入errCall,这很好,但随后它会进入loginSucc。。。

当遇到任何错误回调(这里是errCall或loginErr)时,我想跳出then链。

--编辑--

我想我被误解了,如果出了问题,我想完全打破链条,不检查任何其他"然后"。

就好像我在说:如果第一个然后是错误的,在这里停止,如果第一个,然后可以继续,如果第二个"然后"可以继续,"如果第三个"然后"错误,停止

// 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);
}

我的观点是,如果我有许多"然后"链接的

,我不希望只有一个错误处理程序

实际发生的是:

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

你可以通过调用来打破这个链条

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

在您的errCall()函数中。

编辑:正如OP通过调用$q.reject所指出的,代码将进入loginErr函数。或者,你可以这样修改你的代码:

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

你可以在这两个SO问题中阅读更多:

  1. 打破承诺链
  2. 打破当时的承诺Angularjs

这也是一个有用的阅读:压扁承诺链

errCall函数需要返回一个promise,而该promise需要被拒绝才能触发loginErr。

function errCall(){
   // i do some things here and now
   return $q(function(resolve, reject) {
        // auto reject
        reject();
   });

}

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

只要不将任何errCallloginErr传递给then,并在承诺链的末尾使用catch(),它将在第一个错误时中断,该错误将传递给catch()。如果你想显式处理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'
  }
}

您的最佳选择是返回从未从errCall():解决的承诺

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

但你是对的,你试图做的是"违背承诺的哲学"。

为什么你不应该这么做

当然,当在评估第一个promise的过程中发生错误时,调用loginSucc函数是一个问题。然而,正如其他人已经指出的那样,这可以通过在errCall中再次拒绝来解决。但是您不应该试图避免执行loginErr,否则您的代码在概念上会出现问题。

表达的评价

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

产生另一个承诺。约定是promise有一个then()方法,该方法将两个回调作为参数,一个用于成功,另一个用于失败。合同还规定,在成功评估promise时调用成功回调,在所有其他情况下调用错误/失败回调如果你打算永远不打电话给他们中的任何一个,就不要用承诺