简体   繁体   English

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

[英]Angular $q.all gets called after first promise finished

I'm trying to use $q.all to wait until all promises are resolved but it's called after first promise is finished! 我正在尝试使用$ q.all等到所有的诺言都解决了,但是在第一个诺言完成后会调用它!

What I'm doing wrong? 我做错了什么?

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

EDIT 编辑

Analysing a little bit deeper the problem, this situation occurs when some of the responses are error. 更深入地分析问题,当某些响应出错时,就会发生这种情况。 For example when the server returns header("HTTP/1.0 418 I'm A Teapot: " . $filename); 例如,当服务器返回header("HTTP/1.0 418 I'm A Teapot: " . $filename); , client console would be like: ,客户端控制台如下所示:

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

$q.all is not resilient $q.all 没有弹性

As noted by others, $q.all is not resilient . 正如其他人所指出的那样, $q.all 没有弹性 If one of the promises is rejected, the $q.all is rejected with the first error. 如果其中一个承诺被拒绝,则第一个错误将拒绝$q.all

To create a resilient composite promise, that is a promise that waits for all the promises to complete pass or fail, use .catch on each individual promise to convert the rejected promise to a successful promise. 要创建有弹性的复合承诺,即等待所有承诺完成通过或失败的承诺, .catch对每个单独的承诺使用.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
});

The two things to take away from this answer: 此答案有两点要注意:

  1. A $q.all promise is not resilient . $q.all承诺没有弹性 It is rejected with the first rejected promise. 它被第一个被拒绝的承诺所拒绝。
  2. A fulfilled promise can be created from a rejected promise by returning a value to the onRejected function of either the .then method or the .catch method. 甲诺实现可以从被拒绝的承诺由值返回任一的onRejected函数来创建.then方法或.catch方法。

For more information, see You're Missing the Point of Promises 有关更多信息,请参见您遗失了承诺点

The angular documentation doesn't go into detail, but I believe $q.all() behaves in this case the same way as the es2015 Promise.all() : 角度文档没有详细介绍,但我相信$q.all()在这种情况下的行为与es2015 Promise.all()

If any of the passed in promises rejects, the all Promise immediately rejects with the value of the promise that rejected, discarding all the other promises whether or not they have resolved. 如果任何传入的承诺均被拒绝,则所有Promise都会立即以拒绝的承诺的值来拒绝,并丢弃所有其他承诺,无论它们是否已解决。

Most likely what is happening here is that at least one of your requests is failing. 最有可能发生的情况是您的请求中至少有一个失败了。 Your log statements don't distinguish whether the $q.all() succeeded or failed but if it is failing all you will see is the first error. 您的日志语句不区分$q.all()成功还是失败,但是如果失败,您将看到的只是第一个错误。

See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all for the source of the quote. 请参阅https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/all ,以获取报价来源。

Edit: 编辑:

If you want to get all of the responses, even when some fail, then you should add a catch handler in saveAudit to convert the failures into successful responses: 如果要获得所有响应,即使某些响应失败,也应在saveAudit添加一个catch处理程序,以将失败转换为成功响应:

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

and then you need to check each response to see whether it contains an error or valid data. 然后您需要检查每个响应以查看其是否包含错误或有效数据。

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

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