如何在链式承诺的中间停止/打破

时间:2014-09-22 13:15:25

标签: angularjs angular-promise

我有一连串$ 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;
&#13;
&#13;

2 个答案:

答案 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

&#13;
&#13;
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;
&#13;
&#13;