我有一连串$ http调用服务器。如果一个呼叫失败,我想向用户显示通知并停止链。起初我以为我可以使用$ q.reject来停止链,但事实证明程序流继续到下一个then
的错误处理程序。我也尝试过什么都不返回,但流程仍在继续。
我可以停止流动中链吗?例如,下面的脚本应该打印result: |A|D|F
而不是result: |A|D|F|E|H|J
。
如果流量无法在链中间停止,我是否必须在每个then
的错误处理程序中添加额外条件,还是有更优雅的方式?
angular.module("MyModule", []).controller("MyCtrl", ["$scope", "$q", "$timeout",
function($scope, $q, $timeout) {
$scope.result = "";
var d0 = $q.defer();
$timeout(function() {
d0.reject("A"); // the promise will fail
}, 1000);
d0.promise.then(
function(response) {
$scope.result += "|" + response + "|B";
var d1 = $q.defer();
$timeout(function() {
d1.resolve("C");
}, 1000);
return d1.promise;
},
function(response) {
$scope.result += "|" + response + "|D";
return $q.reject("E");
}
).finally( // it should stop here ...
function() { $scope.result += "|F"; }
).then(
function(response) {
$scope.result += "|" + response + "|G";
},
function(response) { // ... but instead it continues here
$scope.result += "|" + response + "|H";
return $q.reject("I");
}
).finally(
function() { $scope.result += "|J"; }
)
}
]);

<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<div ng-app="MyModule" ng-controller="MyCtrl">
result: {{result}}
</div>
&#13;
答案 0 :(得分:4)
来自$q.reject
documentation:
在将deferreds / promises与熟悉的try / catch / throw行为进行比较时,请将reject视为JavaScript中的throw关键字。这也意味着,如果你&#34;赶上&#34;通过promise错误回调发生错误,并且您希望将错误转发给从当前承诺派生的承诺,您必须&#34;重新抛出&#34;返回通过拒绝构建的拒绝错误。
reject
不会自动中止承诺链,它将继续执行下一个承诺,为剩下的每个承诺调用错误处理程序。
此外,无论链是否出错,finally
回调始终都会运行。如果您不希望它运行,那么您可以手动检查承诺的状态。
编辑:
这是指向如何链接错误的答案的链接:
Break promise chain and call a function based on the step in the chain where it is broken (rejected)
答案 1 :(得分:2)
这是我在阅读@bmceldowney提供的link后得出的结论:
流程将始终转到下一个then
,因此要停止,请不要在需要停止的路径/承诺上提供下一个then
,然后放下then
仅限于需要继续的路径/承诺。
在我的情况下,我不希望链接在第一个承诺收到错误后继续,因此下一个then
应该附加在第二个承诺上,而不是第一个then
:
d0.promise.then(
function(response) {
// ...
return d1.promise.then( // append the next then here ...
// ...
).catch (
// ...
).finally(
// ...
);
}
).catch (
// ...
).finally(
// ...
); // ... instead of here
angular.module("MyModule", []).controller("MyCtrl", ["$scope", "$q", "$timeout",
function($scope, $q, $timeout) {
$scope.result = [];
var d0 = $q.defer();
$timeout(function() { d0.reject(); }, 1000);
d0.promise.then(
function(response) {
$scope.result.push("d0 successful");
var d1 = $q.defer();
$timeout(function() { d1.reject(); }, 1000);
return d1.promise.then(
function(response) { $scope.result.push("d1 successful"); }
).catch (
function(response) { $scope.result.push("d1 failed"); }
).finally(
function() { $scope.result.push("finally2"); }
);
}
).catch (
function(response) { $scope.result.push("d0 failed"); }
).finally(
function() { $scope.result.push("finally1"); }
);
}
]);
&#13;
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<div ng-app="MyModule" ng-controller="MyCtrl">
<p>result:</p>
<div ng-repeat="msg in result">{{msg}}</div>
</div>
&#13;