Angular $q.all 在第一个承诺完成后被调用
Angular $q.all gets called after first promise finished
我正在尝试使用 $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);
});
}
编辑
稍微深入分析一下问题,这种情况是在某些响应错误时出现的。例如,当服务器 returns 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
angular 文档没有详细说明,但我相信 $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.
这里发生的情况很可能是您的至少一个请求失败了。您的日志语句不会区分 $q.all()
是成功还是失败,但如果失败,您将看到的只是第一个错误。
请参阅 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all 了解引述来源。
编辑:
如果您想获得所有响应,即使有些响应失败,那么您应该在 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);
});
}
然后您需要检查每个响应以查看它是否包含错误或有效数据。
$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
});
从这个答案中得出的两点:
$q.all
承诺没有弹性。它被第一个拒绝的承诺拒绝。
- 通过返回一个值给
.then
方法或.catch
方法的onRejected函数,可以从被拒绝的承诺创建一个已实现的承诺.
有关详细信息,请参阅 You're Missing the Point of Promises
我正在尝试使用 $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);
});
}
编辑
稍微深入分析一下问题,这种情况是在某些响应错误时出现的。例如,当服务器 returns 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
angular 文档没有详细说明,但我相信 $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.
这里发生的情况很可能是您的至少一个请求失败了。您的日志语句不会区分 $q.all()
是成功还是失败,但如果失败,您将看到的只是第一个错误。
请参阅 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all 了解引述来源。
编辑:
如果您想获得所有响应,即使有些响应失败,那么您应该在 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);
});
}
然后您需要检查每个响应以查看它是否包含错误或有效数据。
$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
});
从这个答案中得出的两点:
$q.all
承诺没有弹性。它被第一个拒绝的承诺拒绝。- 通过返回一个值给
.then
方法或.catch
方法的onRejected函数,可以从被拒绝的承诺创建一个已实现的承诺.
有关详细信息,请参阅 You're Missing the Point of Promises