简体   繁体   English

处理AngularJS多次调用中的错误

[英]Handling errors in multiple calls of AngularJS promises

I have an AngularJS service with such async API: 我有一个带有这种异步API的AngularJS服务:

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

asyncCall incapsulates multiple calls of $http which handled by $q.all . asyncCall封装由$q.all处理的多个$http调用。 Each of the $http requests can response with error and I want the errors to be handled by one catch handler. 每个$http请求都可以响应错误,我希望错误由一个catch处理程序处理。 So how i can achieve multiple calls of the catch handler ? 那我怎么能实现catch处理程序的多次调用呢?

If I understood correctly (finally), this is what you are trying to achieve: 如果我理解正确(最后),这就是你想要实现的目标:

  • Input: 输入:
    1. a list of promises 承诺清单
    2. a callback to be called when all promises have been resolved 所有承诺都已解决时要调用的回调
    3. a callback to be called each time any of the promises gets rejected 每次任何承诺被拒绝时都要调用的回调

  • Behaviour: 行为:
    1. You want parallel execution (not sequential). 您想要并行执行(不是顺序)。
    2. You want all promises to be either resolved or rejected (ie even if one promise gets rejected, the rest should continue as usual). 您希望所有承诺都得到解决或拒绝(即使一个承诺被拒绝,其余承诺应该像往常一样继续)。
    3. You want the "final" callback to be called exactly once (receiving an array of results - regardless if the respective deferred was resolved or rejected). 您希望将“最终”回调调用一次(接收结果数组 - 无论相应的延迟是否已解决或拒绝)。

$q.all should be "augmented" to suit your needs, because by default: $q.all应该“增强”以满足您的需求,因为默认情况下:

  1. It gets immediatelly rejected as soon as any of the promises in the list gets rejected. 一旦列表中的任何承诺被拒绝,它立即被拒绝。
  2. In case of rejection it returns only the rejection reason and not a list of results. 在拒绝的情况下,它仅返回拒绝原因而不是结果列表。

Here is a possible implementation: 这是一个可能的实现:

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

See, also, this short demo . 另见这个简短的演示

One way, would be to attach a .catch handler indidually in your service: 一种方法是在您的服务中单独附加.catch处理程序:

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

Another way would be to implement a settle method that is like $q.all but keeps track of all results. 另一种方法是实现类似$q.allsettle方法,但跟踪所有结果。 Stealing from my answer here : 从我的回答窃取这里

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

You can handle multiple promises as such: 您可以处理多个承诺:

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

Which gives you access to all results of the promise, regardless if it failed or not, and let you recover with more granularity. 这使您可以访问承诺的所有结果,无论它是否失败,并让您以更细的粒度进行恢复。

Your service should handle that aggregation since it's the one returning a promise on everything. 您的服务应该处理该聚合,因为它是对所有内容返回承诺的聚合。 One example would be to do: 一个例子是:

if(failed.length > 0){
     throw new Error("The following failed..."); // some info about all failed
}

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

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