66

当一些调用有效而另一些调用失败时,$q.all() 会发生什么?

我有以下代码:

    var entityIdColumn = $scope.entityType.toLowerCase() + 'Id';
    var requests = $scope.grid.data
      .filter(function (rowData, i) {
          return !angular.equals(rowData, $scope.grid.backup[i]);
      })
      .map(function (rowData, i) {
          var entityId = rowData[entityIdColumn];
          return $http.put('/api/' + $scope.entityType + '/' + entityId, rowData);
      });
    $q.all(requests).then(function (allResponses) {
        //if all the requests succeeded, this will be called, and $q.all will get an
        //array of all their responses.
        console.log(allResponses[0].data);
    }, function (error) {
        //This will be called if $q.all finds any of the requests erroring.
        var abc = error;
        var def = 99;
    });

当所有的 $http 调用都工作时,allResponses 数组就会被数据填充。

当一个失败时,我的理解是将调用第二个函数并给出错误变量的详细信息。

但是,如果某些响应有效而其他响应失败,有人可以帮我解释一下会发生什么吗?

4

7 回答 7

41

我相信由于 Promise 库是基于Q实现的,一旦第一个 Promise 被拒绝,就会调用拒绝回调并显示错误。它不会等待其他承诺解决。Q 请参阅https://github.com/kriskowal/q的文档。对于 Q.all 这就是提到的

all 函数返回一个值数组的承诺。当这个 Promise 被实现时,数组包含原始 Promise 的实现值,与这些 Promise 的顺序相同。如果给定的 Promise 之一被拒绝,返回的 Promise 将立即被拒绝,而不是等待批处理的其余部分。

于 2013-11-13T04:16:03.393 回答
41

自从这个问题发布以来已经有一段时间了,但也许我的回答可能仍然对某人有所帮助。我通过简单地解决所有承诺解决了一个类似的问题,但是通过返回我可以稍后处理并查看是否有任何错误。这是我用于预加载一些图像资产的示例:

var loadImg = function(imageSrc) {
    var deferred = $q.defer();

    var img = new Image();
    img.onload = function() {
        deferred.resolve({
            success: true,
            imgUrl: imageSrc
        });
    };
    img.onerror = img.onabort = function() {
        deferred.resolve({
            success: false,
            imgUrl: imageSrc
        });
    };
    img.src = imageSrc;

    return deferred.promise;
}

后来我可以看到哪些是错误的:

var promiseList = [];
for (var i = 0; i < myImageList.length; i++) {
    promiseList[i] = loadImg(myImageList[i]);
}
$q.all(promiseList).then(
    function(results) {
        for (var i = 0; i < results.length; i++) {
            if (!results[i].success) {
                // these are errors
            }
        }
    }
);
于 2014-06-02T10:00:29.923 回答
6

编辑:仅在 Kris Kowal 的 Q 中支持 - 但仍然是一个有用的花絮

如果您想处理所有这些而不立即拒绝失败,请使用allSettled

这是文档所说的:

如果你想等待所有的承诺被履行或拒绝,你可以使用 allSettled。

Q.allSettled(promises)
.then(function (results) {
    results.forEach(function (result) {
        if (result.state === "fulfilled") {
            var value = result.value;
        } else {
            var reason = result.reason;
        }
    });
});
于 2014-10-01T12:40:11.390 回答
5

这是一个小答案。在这个小提琴中,你可以看到它是如何工作的,如果某个 promise 发生错误。

$q.all([test1(), test2()]).then(function() {
  // success
}, function() {
  // error
});

http://jsfiddle.net/wd9w0ja4/

于 2015-08-18T07:37:11.000 回答
4

我发现了一个新的 angular 包,它将 allSettled 功能添加到 angular 中的 $q:

https://github.com/ohjames/angular-promise-extras

于 2015-08-14T10:55:24.790 回答
1

就我而言,无论成功还是失败,我都需要知道最后一个承诺何时解决。$q.all 不是一种选择,因为如果失败,它会立即关闭。我需要这个来确保无论如何都会重定向用户,但前提是所有数据都已处理(或不处理),以便它们可以加载到下一页。所以我最终得到了这个:

  1. 每个实现的承诺/调用也失败回调,其中“重定向”函数在成功和失败回调中都被调用。
  2. 在此函数中设置计数器,每次调用都会增加计数器。如果这达到了承诺/调用的数量,则重定向到下一个视图。

我知道这是一种很蹩脚的方法,但它对我有用。

于 2016-11-30T14:52:26.360 回答
1

在将 $http 承诺传递给 $q 之前,您不能简单地处理错误条件吗?承诺是链式的,所以这应该有效:

return $http.put('/api/' + $scope.entityType + '/' + entityId, rowData).then(function(r){return r;}, angular.noop);

显然,您可以将 noop 更改为您想要的任何转换,但这可以防止拒绝,从而防止$q.all失败。

于 2017-06-20T00:13:56.320 回答