用errorCallback打破Promise“then”链

时间:2015-12-21 15:38:41

标签: javascript angularjs promise angular-promise

- 编辑 -

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

考虑以下代码:

// 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()出现问题,这就是show:

  • errCall,loginSucc

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

  • errCall,loginErr

这就是我想要的:

  • errCall ...完成,停在这里

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

我想在遇到任何errorCallback(这里是errCall或loginErr)时突破当时的链。

- 编辑 -

我认为我被某种意思误解了,如果出现问题,我想完全打破连锁而不检查任何其他“然后”。

好像我在说:如果先错了就停在这里,如果先是然后确定继续,如果第二个“然后”确定继续,如果第三个“然后”错了,停止

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

我的观点是,如果我有很多“然后”链接

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

4 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:2)

实际发生的是:

    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)

您可以在这两个问题中阅读更多内容:

  1. Break promise chain
  2. Break Out of then promises in Angularjs
  3. 这也是一个有用的读物​​:Flattening Promise Chains

答案 2 :(得分:1)

只是不要将任何errCallloginErr传递给then并在promise链的末尾使用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'
  }
}

答案 3 :(得分:0)

您最好的选择是返回一个永远不会从errCall()解决的承诺:

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

但你是对的,你要做的是“反对承诺的哲学”。

为什么你不应该这样做

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

表达式的评估

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

产生另一个承诺。合同是承诺有一个then()方法,将两个回调作为参数,一个用于成功,一个用于失败。合同还包括成功评估promise并在所有其他情况下调用错误/失败回调时调用成功回调。 如果您打算永远不打电话给任何一方,请不要使用承诺!