Search code examples
javascriptangularjspromisenested-loopsangular-promise

loop of promises after a single promise


I just have to write a promise, then, with the result of this promise, an array of movies, I have to loop inside the array and for each element do a remote call (with promise too) to decorate with additional data. I tried this way:

var deferred = $q.defer();
var promises = [];

angular.forEach(tree, function(node) {
    promises.push(
        APICall.GetMovieList(node).then(function(success){
            var contents = {};
            //simple data manipulation
            return contents;
        })
        .then(function(contents){ /////////////////////// concatenation part that won't work
            angular.forEach(contents, function(content) {
                APICall.GetMovieDetails(content.ID).then(function(success){
                    content.metadata = success.metadata;    
                });
            });
            return contents;
        })
    );
});


$q.all(promises).then(ResolveFunction);

return deferred.promise;

For the sake of readability I deleted the ResolveFunction, it simply manage the promise array and do a $q.resolve(results). The thing is that without the concatenation it works like a charm, but with the necessary concatenation it does just return the same result as before, it behave like this due to async calls that will be called after... Is it a good idea to create another deferred and nest a $q.all inside the concatenation part and return the $q.all solved array promise? Thanks so much


Solution

  • You don't need to create a second deferred (you don't need a deferred at all).
    Simply do the following:

    var promises = [];
    
    angular.forEach(tree, function(node) {
        promises.push(
            APICall.GetMovieList(node).then(function(success){
                var contents = {};
                //simple data manipulation
                return contents;
            })
            .then(function(contents){ 
                var contentPromises = [];
                angular.forEach(contents, function(content) {
                    contentPromises.push(
                        APICall.GetMovieDetails(content.ID).then(function(success){
                            content.metadata = success.metadata;    
                        })
                    );
                });
                return $q.all(contentPromises).then(function() {
                    return contents;
                });
            })
        );
    });
    
    return $q.all(promises).then(function(nodes) {
        return nodes;
    });
    

    Here is a working jsfiddle-demo with a mocked APICall-Factory.