第一个承诺完成后,Angular $ q.all被调用

时间:2016-01-19 12:23:41

标签: javascript angularjs promise angular-promise

我试图使用$ q.all等待所有承诺得到解决但在第一次承诺完成后调用它!

我做错了什么?

function sendAudits(audits) {
    var promises = [];

    $scope.sendAudits = {
        progress: 0
    };
    angular.forEach(audits, function (audit, idAudit) {
        promises.push(saveAudit(audit));
    });

    $q
        .all(promises)
        .then(function (data) {
            console.log(data);
        }, function (errors) {
            console.log(errors);
        });
}

function saveAudit(audit) {
    var filename = audit.header.id + ".txt";

    return $http({
        method: 'PUT',
        url: '/audits/audits.php?filename=' + encodeURIComponent(filename),
        data: AuditSvc.getPlainAudit(audit.header.id)
    }).finally(function () {
        $scope.sendAudits.progress += 1;
        console.log("FINALLY: " + audit.header.id);
    });
}

修改

更深入地分析问题,当某些响应出错时会出现这种情况。例如,当服务器返回header("HTTP/1.0 418 I'm A Teapot: " . $filename);时,客户端控制台就像:

PUT http://localhost:8182/audits/audits.php?filename=1.txt 418 (I'm A Teapot: 1.txt)
FINALLY: 1
Object {data: "", status: 418, config: Object, statusText: "I'm A Teapot: 1.txt"}
PUT http://localhost:8182/audits/audits.php?filename=2.txt 418 (I'm A Teapot: 2.txt)
FINALLY: 2
PUT http://localhost:8182/audits/audits.php?filename=3.txt 418 (I'm A Teapot: 3.txt)
FINALLY: 3
PUT http://localhost:8182/audits/audits.php?filename=4.txt 418 (I'm A Teapot: 4.txt)
FINALLY: 4

2 个答案:

答案 0 :(得分:3)

$q.all 无弹性

正如其他人所说,$q.all 没有弹性。如果其中一个承诺被拒绝,$q.all将被拒绝并出现第一个错误。

要创建弹性复合承诺,这是一个等待所有承诺完成通过或失败的承诺,请对每个承诺转换.catch强烈的>被拒绝的成功承诺的承诺。

var resilientPromises = [];

angular.forEach(promises, function(p) {
    var resilientP = p.catch( function(result) {
        //return to convert rejection to success
        return result;
    });
    resilientPromises.push(resilientP);
});

$q.all(resilientPromises).then( function (results) {
    //process results
});

从这个答案中可以看出两件事:

  1. $q.all承诺不具弹性。它被第一个被拒绝的承诺拒绝。
  2. 可以通过值返回<{1}}方法或.then方法的onRejected函数,从已拒绝的承诺中创建已履行的承诺。
  3. 有关详细信息,请参阅You're Missing the Point of Promises

答案 1 :(得分:2)

角度文档没有详细说明,但我相信Promise.all()在这种情况下的行为与es2015 $q.all()相同:

  

如果任何传入的承诺拒绝,则所有承诺立即拒绝拒绝的承诺的价值,放弃所有其他承诺,无论他们是否已经解决。

最有可能的是,至少有一个请求失败了。您的日志语句无法区分catch是成功还是失败,但如果失败,您将看到的是第一个错误。

请参阅https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all了解报价来源。

修改

如果您想获得所有响应,即使某些响应失败,那么您应该在saveAudit中添加function saveAudit(audit) { var filename = audit.header.id + ".txt"; return $http({ method: 'PUT', url: '/audits/audits.php?filename=' + encodeURIComponent(filename), data: AuditSvc.getPlainAudit(audit.header.id) }).catch(function(error) { return { error:error}; }) .finally(function () { $scope.sendAudits.progress += 1; console.log("FINALLY: " + audit.header.id); }); } 处理程序以将失败转换为成功的响应:

{{1}}

然后您需要检查每个响应以查看它是否包含错误或有效数据。