简体   繁体   English

多个 $http 上的 Angular 承诺

[英]Angular promise on multiple $http

I am trying to do multiple $http call and my code looks something like this:我正在尝试执行多个$http调用,我的代码如下所示:

var data = ["data1","data2","data3"..."data10"];

for(var i=0;i<data.length;i++){
    $http.get("http://example.com/"+data[i]).success(function(data){
        console.log("success");
    }).error(function(){
        console.log("error");
    });
}

How can I have the promise to know all $http call is successfull?我怎么能保证知道所有$http调用都成功了? If anyone of it fail, will perform some action.如果其中任何一个失败,将执行一些操作。

You could also use $q.all() method.您也可以使用$q.all()方法。

So, from your code:所以,从你的代码:

var data = ["data1","data2","data3"..."data10"];

for(var i=0;i<data.length;i++){
    $http.get("http://example.com/"+data[i]).success(function(data){
        console.log("success");
    }).error(function(){
        console.log("error");
    });
}

You could do:你可以这样做:

var promises = [];
data.forEach(function(d) {
  promises.push($http.get('/example.com/' + d))
});
$q.all(promises).then(function(results){
  results.forEach(function(data,status,headers,config){
    console.log(data,status,headers,config);
  })
}),

This above basically means execute whole requests and set the behaviour when all have got completed.上面这基本上意味着执行整个请求并在所有请求都完成后设置行为。

On previous comment: 在之前的评论中:

Using status you could get to know if any have gone wrong.使用状态你可以知道是否有任何错误。 Also you could set up a different config for each request if needed (maybe timeouts, for example).如果需要,您还可以为每个请求设置不同的配置(例如,可能超时)。

If anyone of it fail, will perform some action.如果其中任何一个失败,将执行一些操作。

From docs which are also based on A+ specs:来自同样基于 A+ 规范的文档

$q.all(successCallback, errorCallback, notifyCallback);

If you are looking to break out on the first error then you need to make your for loop synchronous like here: Angular synchronous http loop to update progress bar如果您想解决第一个错误,那么您需要使您的 for 循环像这里一样同步Angular synchronous http loop to update progress bar

var data = ["data1", "data2", "data3", "data10"];
$scope.doneLoading = false;
var promise = $q.all(null);

angular.forEach(data, function(url){
  promise = promise.then(function(){
    return $http.get("http://example.com/" + data[i])
      .then(function (response) {
        $scope.data = response.data;
      })
      .catch(function (response) {
        $scope.error = response.status;
      });
  });
});

promise.then(function(){
  //This is run after all of your HTTP requests are done
  $scope.doneLoading = true;
});

If you want it to be asynchronous then: How to bundle Angular $http.get() calls?如果您希望它是异步的,那么: 如何捆绑 Angular $http.get() 调用?

app.controller("AppCtrl", function ($scope, $http, $q) {
  var data = ["data1", "data2", "data3", "data10"];
  $q.all([
    for(var i = 0;i < data.length;i++) {
      $http.get("http://example.com/" + data[i])
        .then(function (response) {
          $scope.data= response.data;
        })
        .catch(function (response) {
          console.error('dataerror', response.status, response.data);
          break;
        })
        .finally(function () {
          console.log("finally finished data");
        });
    }
  ]).
  then(function (results) {
    /* your logic here */
  });
};

This article is pretty good as well: http://chariotsolutions.com/blog/post/angularjs-corner-using-promises-q-handle-asynchronous-calls/这篇文章也很不错: http : //chariotsolutions.com/blog/post/angularjs-corner-using-promises-q-handle-asynchronous-calls/

Accepted answer is okay, but is still a bit ugly.接受的答案还可以,但仍然有点难看。 You have an array of things you want to send.. instead of using a for loop, why not use Array.prototype.map ?你有一系列想要发送的东西......而不是使用for循环,为什么不使用Array.prototype.map

var data = ["data1","data2","data3"..."data10"];

for(var i=0;i<data.length;i++){
    $http.get("http://example.com/"+data[i]).success(function(data){
        console.log("success");
    }).error(function(){
        console.log("error");
    });
}

This becomes这变成

var data = ['data1', 'data2', 'data3', ...., 'data10']
var promises = data.map(function(datum) {
  return $http.get('http://example.com/' + datum)
})
var taskCompletion = $q.all(promises)
// Usually, you would want to return taskCompletion at this point,
// but for sake of example

taskCompletion.then(function(responses) {
  responses.forEach(function(response) {
    console.log(response)
  })
})

This uses a higher order function so you don't have to use a for loop, looks a lot easier on the eyes as well.这使用了高阶函数,因此您不必使用for循环,看起来也容易多了。 Otherwise, it behaves the same as the other examples posted, so this is a purely aesthetical change.否则,它的行为与发布的其他示例相同,因此这纯粹是美学上的变化。

One word of warning on success vs error - success and error are more like callbacks and are warnings that you don't know how a promise works / aren't using it correctly.关于successerror一个警告词 - successerror更像是回调,并且警告您不知道承诺如何工作/未正确使用它。 Promises then and catch will chain and return a new promise encapsulating the chain thus far, which is very beneficial. Promises thencatch将链接并返回一个新的 Promise 封装到目前为止的链,这是非常有益的。 In addition, using success and error (anywhere else other than the call site of $http ) is a smell, because it means you're relying explicitly on a Angular HTTP promise rather than any A+ compliant promise.此外,使用successerror (除了$http的调用站点之外的任何其他地方)是一种味道,因为这意味着您明确依赖 Angular HTTP 承诺,而不是任何符合 A+ 的承诺。

In other words, try not to use success / error - there is rarely a reason for them and they almost always indicate a code smell because they introduce side effects.换句话说,尽量不要使用success / error ——它们很少有原因,它们几乎总是表明代码异味,因为它们引入了副作用。


With regards to your comment:关于你的评论:

I have did my own very simple experiment on $q.all.我在 $q.all 上做了我自己的非常简单的实验。 But it only trigger when all request is success.但它仅在所有请求成功时触发。 If one if it fail, nothing happen.如果失败,则什么也不会发生。

This is because the contract of all is that it either resolves if every promise was a success, or rejects if at least one was a failure.这是因为all的契约是,如果每一个承诺都成功,它要么解决,要么如果至少一个承诺失败,则拒绝。

Unfortunately, Angular's built in $q service only has all ;不幸的是,Angular 内置的$q服务只有all if you want to have rejected promises not cause the resultant promise to reject, then you will need to use allSettled , which is present in most major promise libraries (like Bluebird and the original Q by kriskowal).如果您希望拒绝的承诺不会导致最终的承诺被拒绝,那么您将需要使用allSettled ,它存在于大多数主要的承诺库中(如 Bluebird 和 kriskowal 的原始Q )。 The other alternative is to roll your own (but I would suggest Bluebird).另一种选择是推出自己的(但我建议蓝鸟)。

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

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