Angular - .finally() 是否在链式承诺决策树中的每条路径的末尾调用?

Angular - Is .finally() Called At the End of Every Path in a Chained Promise Decision Tree?

我有以下连锁的承诺序列:

$scope.promisesInProgress = true
myService.myFirstPromise(id)
    .then(function(data){
        $scope.firstResponse = data;
        return myService.mySecondPromise(id);
    })
    .then(function(data){
        $scope.secondResponse = data;
    })
    .finally(function(){
        $scope.promisesInProgress = false;
    });

无论前两个promise成功/失败,是否都在最后调用了finally()回调函数?

例如,如果 myFirstPromise() return 发出 400 响应,mySecondPromise() 将永远不会被调用 - 但我假设 finally() 块仍会被抛出?如果 mySecondPromise() returns a 400(并且 $scope.secondResponse 从未设置)并且如果两个承诺 return 200s.

Angular 1.x $q 服务灵感来自 Kris Kowal 的 Q,基于 docs:

finally(callback, notifyCallback) – allows you to observe either the fulfillment or rejection of a promise, but to do so without modifying the final value. This is useful to release resources or do some clean-up that needs to be done whether the promise was rejected or resolved. See the full specification for more information.

所以是的,无论 myFirstPromise 解决还是拒绝,finally() 块都会被调用

已更新,

请注意,myFirstPromisefinally() 块将在 mySecondPromise 解决(或拒绝)之前调用,因为 myFirstPromisemySecondPromise 是不同的 promise 实例,mySecondPromisemyFirstPromise 解决后创建的 promise 实例

我写了一个 Jasmine 测试来查看 finally() 块是否在每个函数执行时被调用,无论链接的承诺返回什么。

describe('myController Test Suite', function(){

    var q, scope, deferred, myService;

    // Initialize the Pointivo module
    beforeEach(function(){
        module('myApp');
    });

    // Mock out fake service
    beforeEach(function(){
        myService = {
            myFirstPromise: function(){
                deferred = q.defer();
                // TEST ME
                deferred.resolve('first promise response');
                return deferred.promise;
            },
            mySecondPromise: function(){
                deferred = q.defer();
                // TEST ME
                deferred.resolve('second promise response');
                return deferred.promise;
            },
            myThirdPromise: function(){
                deferred = q.defer();
                // TEST ME
                deferred.resolve('third promise response');
                return deferred.promise;
            }
        };
        spyOn(myService, 'myFirstPromise').and.callThrough();
        spyOn(myService, 'mySecondPromise').and.callThrough();
        spyOn(myService, 'myThirdPromise').and.callThrough();
    });

    // Assign controller scope and service references
    beforeEach(inject(function($controller, $rootScope, $q){
        scope = $rootScope.$new();
        q = $q;
        $controller('myController', {
            $scope: scope,
            myService: myService
        });
    }));

    describe('finally test', function(){
        it('should always hit the finally statement', function(){
                scope.finallyStatementFlag = false;
            scope.test();
            scope.$apply();
            expect(scope.finallyStatementFlag).toBeTruthy();
        });
    });

});

以上假设控制器看起来像:

myApp.controller('myController', function($scope, myService){

    $scope.finallyStatementFlag = false;

    $scope.test = function(){
        myService.myFirstPromise()
            .then(function(data){
                console.log(data);
                return myService.mySecondPromise()
            })
            .then(function(data){
                console.log(data);
                return myService.myThirdPromise();
            })
            .then(function(data){
                console.log(data);
            })
            .finally(function(){
                console.log('finally statement');
                $scope.finallyStatementFlag = true;
            });
    }

});

即使您在我们定义 myService.[=18 的 beforeEach() 回调中将任何或所有 deferred.resolve() 更改为 deferred.reject(),以上内容也会通过=]

Fiddle example