Mero
Mero

Reputation: 632

Angular JS waiting for all the promises to be resolved

Am looping over an array and making async calls to an api the returned data need to me merged with a different array the problem am facing when the merge occurs some of the promises have not being resolved yet so the resulting array after the merge is missing data . any ideas how to go about this . (am new to Angular). the array am looping through has at least 200 elements (I don't know the size of the array in advance) i get the id from each element and i call this service:

for (i = 0; i < list.length; i++) {
     service.getRawHtml(list[i].service_object_id)
        .then(function(res){
            temp=htmlToArray(res);
            htmlDataList.push(temp);
    }, function(err){
         // error
    })
    }



service.getRawHtml=function (id){ 
   var defer = $q.defer();
        $http({
            method: 'GET',
            url: 'http://wlhost:50000/'+id
        }).success(function (response) {
            defer.resolve(response);
        }).error(function (data, status) {
            console.log("Failure");
            defer.reject(err);
    });
    return defer.promise;
}

Thanks in advance.

Upvotes: 0

Views: 2375

Answers (3)

Mortalus
Mortalus

Reputation: 10712

just to clerify @nodes solution:

var promisesToWaitFor = [];
for (i = 0; i < list.length; i++) {
    var promis = service.getRawHtml(list[i].service_object_id)
    promisesToWaitFor.push(promis)
}
$q.all(promisesToWaitFor).then(function(resultsArray) {
    var flatten = [].concat.apply([],resultsArray);
    temp=htmlToArray(flatten);
    htmlDataList.push(temp);
}, function(err) {
    // error
});

Upvotes: 2

Daniel B
Daniel B

Reputation: 8879

As @ndoes suggests, this can be done with $q.all(), which takes an array of promises and resolves when all of them are resolved, or rejects if any of them is rejected.

You're calling the asynchronous function inside the for loop which will execute, but as soon as all of the function calls have been made, the code will continue synchronously. There wont be any magical awaiting for all the promises to resolve.

What you instead should do is to push all of the returning promises to an array, then use $q.all() to await them all.

//Declare an array to which we push the promises
var promises = [];

for (i = 0; i < list.length; i++) {
    //Call the service and push the returned promise to the array
    promises.push(service.getRawHtml(list[i].service_object_id));
}

//Await all promises
$q.all(promises)
    .then(function(arrayOfResults){
        //Use your result which will be an array of each response after
        //it's been handled by the htmlToArray function
    })
    .catch(function(err){
        //Handle errors
    });

I took the opportunity to refactor your code at the same time, as it is implementing the deferred anti-pattern. Since $http already returns a promise, there's no need to create and return a new one. Simply return it right away like

service.getRawHtml = function (id){ 
   return $http({
            method: 'GET',
            url: 'http://wlhost:50000/'+id
        }).success(function (response) {
            return htmlToArray(response);
        }).error(function (data, status) {
            console.log("Failure");
            $q.reject(error);
    });
}

Upvotes: 2

ndoes
ndoes

Reputation: 678

Use $q.all - From the documentation:

Combines multiple promises into a single promise that is resolved when all of the input promises are resolved.

Example usage:

    $q.all([
        getPromise(),
        getPromise(),
        getPromise() 
    ]).then(function(value) {
        $scope.result1 = value[0];
        $scope.result2 = value[1];
        $scope.result3 = value[2];
    }, function(reason) {
        $scope.result = reason;
    });

Upvotes: 4

Related Questions