处理AngularJS多次调用中的错误

时间:2014-04-29 13:50:43

标签: javascript angularjs promise q

我有一个带有这种异步API的AngularJS服务:

myService.asyncCall(['id0', 'id3', 'id2']).then(function (complexData) {   
  // handle complexData
}).catch(function (error) {   
  console.log(error); 
});

asyncCall包含由$http处理的多个$q.all来电。每个$http请求都可以响应错误,我希望错误由一个catch处理程序处理。那么我怎样才能实现catch处理程序的多次调用?

2 个答案:

答案 0 :(得分:5)

如果我理解正确(最后),这就是你想要实现的目标:

  • 输入:
    1. 承诺清单
    2. 在所有承诺都已解决时调用的回调
    3. 每次承诺被拒绝时都会调用回调

  • 行为:
    1. 您想要并行执行(不是顺序执行)。
    2. 您希望所有承诺都得到解决或拒绝(即使一个承诺被拒绝,其余承诺应该照常继续)。
    3. 你想要" final"回调只被调用一次(接收结果数组 - 无论相应的延期被解决还是被拒绝)。

$q.all应该是"扩充"为了满足您的需求,因为默认情况下:

  1. 一旦列表中的任何承诺被拒绝,立即就会被拒绝。
  2. 如果拒绝,则仅返回拒绝原因,结果列表。

  3. 这是一个可能的实现:

    function asyncCall(listOfPromises, onErrorCallback, finalCallback) {
    
      listOfPromises  = listOfPromises  || [];
      onErrorCallback = onErrorCallback || angular.noop;
      finalCallback   = finalCallback   || angular.noop;
    
      // Create a new list of promises that can "recover" from rejection
      var newListOfPromises = listOfPromises.map(function (promise) {
        return promise.catch(function (reason) {
    
          // First call the `onErrroCallback`
          onErrorCallback(reason);
    
          // Change the returned value to indicate that it was rejected
          // Based on the type of `reason` you might need to change this
          // (e.g. if `reason` is an object, add a `rejected` property)
          return 'rejected:' + reason;
    
        });
      });
    
      // Finally, we create a "collective" promise that calls `finalCallback` when resolved.
      // Thanks to our modifications, it will never get rejected !
      $q.all(newListOfPromises).then(finalCallback);
    }
    

    另请参阅此 short demo

答案 1 :(得分:1)

一种方法是将.catch处理程序单独附加到您的服务中:

function asyncCall(urls){
    var calls = urls.map(makeSomeCall).
                map(function(prom){ return prom.catch(e){ /* recover here */});
    return $q.all(calls);
};

另一种方法是实现类似settle的{​​{1}}方法,但会跟踪所有结果。从我的回答中窃取here

$q.all

你可以处理多个承诺:

function settle(promises){
     var d = $q.defer();
     var counter = 0;
     var results = Array(promises.length);
     promises.forEach(function(p,i){ 
         p.then(function(v){ // add as fulfilled
              results[i] = {state:"fulfilled", promise : p, value: v};
         }).catch(function(r){ // add as rejected
              results[i] = {state:"rejected", promise : p, reason: r};
         }).finally(function(){  // when any promises resolved or failed
             counter++; // notify the counter
             if (counter === promises.length) {
                d.resolve(results); // resolve the deferred.
             }
         });
     });
})

这使您可以访问承诺的所有结果,无论它是否失败,并让您以更细的粒度进行恢复。

您的服务应该处理该聚合,因为它是对所有内容返回承诺的聚合。一个例子是:

var promiseArr = ["id0","id3","id2"].map(makePromise);

settle(promiseArr).then(function(results){
    var failed = results.filter(function(r){ return r.state === "rejected"; });
    var failedValues = failed.map(function(i){ return i.value; });
    var done = results.filter(function(r){ return r.state === "fulfilled"; });
     var doneValues = done.map(function(i){ return i.value; }); 
});