Search code examples
javascriptangularjsasynchronouspromisechaining

Promise chaining (angular javascript)


So I have a few functions that all make async calls to a service. I wan't them all to execute after the previous one is complete but only if the previous one didn't fail. It looks something like this:

var fn1 = function() {
    var promise = aService.fn1();
    var successCallback = function(response) {
        return true;
    };
    var errorCallback = function() {
        return false;
    };
    return promise.then(successCallback, errorCallback);
};
var fn2 = function() {
    var promise = aService.fn2();
    var successCallback = function(response) {
        return true;
    };
    var errorCallback = function() {
        return false;
    };
    return promise.then(successCallback, errorCallback);
};
var fn3 = function() {
    var promise = aService.fn3();
    var successCallback = function(response) {
        return true;
    };
    var errorCallback = function() {
        return false;
    };
    return promise.then(successCallback, errorCallback);
};

fn1().then(function(resp){
    if (resp)
    {
        fn2().then(function(resp){
            if (resp)
            {
                fn3().then(function(resp){
                    if (resp)
                    {
                        // all functions have been called in order were successful
                    }
                });
            }
        });
    }
});

The execution at the end looks pretty bad the more function are added to this chain. I wan't to know if there is another way I can structure this in way so it behaves the same but doesn't create a huge tree of chained async calls. If I can keep it on the same indentation that would be great. Thank you!


Solution

  • You have to modify the error callbacks to return $q.reject() instead of false, i.e.:

    var fn1 = function() {
        var promise = aService.fn1();
        var successCallback = function(response) {
            // no return needed, unless the next stage
            // requires the results of this stage
        };
        var errorCallback = function() {
            return $q.reject();
        };
        return promise.then(successCallback, errorCallback);
    };
    

    The the chaining becomes:

    fn1()
        .then(function() {
            return fn2();
        })
        .then(function() {
            return fn3();
        })
        .then(function() {
            // ALL SUCCEEDED HERE
        });
    

    In fact you do not even have to write that painful code in f1, f2, f3, i.e. the following will also do the job:

    aService.fn1()
        .then(function() {
            return aService.fn2();
        })
        .then(function() {
            return aService.fn3();
        })
        .then(function() {
            // ALL SUCCEEDED HERE
        });