【问题标题】:Angular promise on multiple $http多个 $http 的 Angular 承诺
【发布时间】:2015-12-24 00:06:23
【问题描述】:

我正在尝试进行多次$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");
    });
}

我怎样才能保证知道所有$http 呼叫是否成功?如果其中任何一个失败,将执行一些操作。

【问题讨论】:

  • 您可能想查看$q 服务,特别是$q.all。
  • @CollinD 我在$q.all 上做了我自己非常简单的实验。但它只有在所有请求都成功时才会触发。如果一个失败了,什么都不会发生。
  • 如果失败了,什么都不会发生 - 在这种情况下你使用 .all 错误
  • @user1995781 发生这种情况的原因是因为这是all 的预期行为。如果即使子 Promise 被拒绝,您也希望聚合 Promise 得到解决,您需要考虑使用 allSettled。不幸的是,这个方法不在 Angular 的 $q 库中,但它在 Promises 的大牌库中,比如 Bluebird。

标签: javascript angularjs promise angular-promise


【解决方案1】:

如果您希望突破第一个错误,那么您需要像这里一样使您的 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;
});

如果你希望它是异步的,那么:How to bundle Angular $http.get() calls?

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

这篇文章也不错:http://chariotsolutions.com/blog/post/angularjs-corner-using-promises-q-handle-asynchronous-calls/

【讨论】:

  • 感谢您的回答。我已经尝试过您的解决方案,但是当其中一个失败时它什么也没做。当其中一个失败时,我怎样才能得到响应?
  • 我添加了更新的答案,尝试使用 .then、.catch、.finally 代替 .success、.error peterbe.com/plog/promises-with-$http
  • 如果还是不行,你能不能打破 .catch 或 error 上的 for 循环
  • 我添加了一个同步场景。这就是您真正要求的在第一次中断时会失败的循环吗?
  • 请考虑编辑您的帖子,以添加更多关于您的代码的作用以及它为何能解决问题的说明。一个大部分只包含代码的答案(即使它正在工作)通常不会帮助 OP 理解他们的问题。
【解决方案2】:

您也可以使用$q.all() 方法。

所以,从你的代码:

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

你可以这样做:

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

这基本上意味着执行整个请求并设置所有完成后的行为。

On previous comment:

使用状态您可以了解是否有任何问题。如果需要(例如超时),您还可以为每个请求设置不同的配置。

如果其中任何一个失败,将执行一些操作。

From docs 也是based on A+ specs:

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

【讨论】:

  • 感谢您的回答。尝试使用您的代码。如果一个失败,它不会执行$q.all(promises).then(function(results){中的代码
  • 哪一个失败了?你能分享更多你的代码吗?
  • 我的意思是如果 $http 调用中的任何一个失败(例如返回 404 错误),它将不会执行 $q.all() 代码。我现在正在研究实验代码。所以代码和你提供的答案一样干净。
  • 请检查我的最后一个编辑,添加第二个回调,甚至是第三个,因为你正在试验。 Angular 会将 200 到 299 之间的任何状态码解释为成功,其余的解释为错误,因此您可以使用具有相同参数的 errorCallback
【解决方案3】:

接受的答案还可以,但还是有点难看。您有一系列要发送的内容.. 与其使用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");
    });
}

这就变成了

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

这使用了更高阶的函数,因此您不必使用for 循环,看起来也更容易。否则,它的行为与发布的其他示例相同,因此这纯粹是美学上的变化。

success 与 error - success 和 error 上的一个警告词更像是回调,并且是警告您不知道承诺如何工作/没有正确使用它。 Promise then 和 catch 将链接并返回一个新的 Promise 封装迄今为止的链,这是非常有益的。此外,使用success 和error($http 的调用站点以外的任何其他地方)是一种异味,因为这意味着您明确依赖于 Angular HTTP 承诺,而不是任何符合 A+ 的承诺。

换句话说,尽量不要使用success/error - 它们很少有原因,而且它们几乎总是表明代码异味,因为它们会引入副作用。


关于您的评论:

我在 $q.all 上做了我自己的非常简单的实验。但它只有在所有请求都成功时才会触发。如果一个失败了,什么都不会发生。

这是因为all 的约定是,它要么解析如果每个承诺都成功,要么如果至少有一个失败则拒绝。 p>

不幸的是,Angular 内置的$q 服务只有all;如果您希望拒绝的承诺不会导致最终的承诺被拒绝,那么您将需要使用allSettled,它存在于大多数主要的承诺库中(如 Bluebird 和 kriskowal 的原始 Q)。另一种选择是自己动手(但我建议 Bluebird)。

【讨论】:

    猜你喜欢
    • 2014-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-26
    • 2015-11-04
    • 1970-01-01
    • 2017-01-20
    • 1970-01-01
    相关资源
    最近更新 更多