$q promise with Underscore _each
Asked Answered
C

3

5

So I have a method in a angularjs server that is calling a method that returns a promise for each method in a array. I am using underscore _each to loop through the array. I want to wait until the entire array is processed before I call the final line of code in the method..

So...

function ProcessCoolStuff(coolStuffs)
{
 var stuff = [];
 _.each(coolStuffs, function(coolStuff)
 {
   //Some method using $q to return 
   makeStuffCooler(coolStuff).then(function(coolerStuff)
  {
   stuff.push(coolerStuff);
  });
 });
 //Maybe Call a Display Method, or call event ect.. 
 ShowAllMyCoolStuff(stuff);
}

This of course does not work.. the loop completes and calls 'ShowAllMyCoolStuff' before the makeStuffCooler is done for each item. So.. what is the correct way to interact with the async method so my ShowAllMyCoolStuff method will wait until the collection is populated? This may be my lack of experience with $q and promises in general, but I am stuck. Thanks in advance.

Conversational answered 4/9, 2014 at 17:38 Comment(1)
Worth noting that if your browser is running angular, you can probably rely on it to have Array.prototype.forEach and Array.prototype.map.But yeah, $q.all is where it's at.Vegetal
D
8

You want to use $q.all, which takes an array of promises. So use map instead of each, and pass the result to $q.all(), which gives you a promise that waits for all of them. You don't even need that stuff array which is manually filled, but just can use the resolution value of that new promise.

function processCoolStuff(coolStuffs) {
    return $q.all(_.map(coolStuffs, makeStuffCooler));
}
processCoolStuff(…).then(showAllMyCoolStuff);
Domoniquedomph answered 4/9, 2014 at 17:43 Comment(1)
Nice, thanks. That is exactly what I needed.. I figured it had something to do with $q.all.. Also +1 on getting rid of the manually filled array.Conversational
D
0
$q.all([promise1,promise2,promise3,etc])
.then(function(results){
   alert("This alert will happen after all promises are resolved.");
 })
Debbidebbie answered 4/9, 2014 at 17:42 Comment(0)
E
0

after I read the question and the according answer, I got on the right track. Thanks so far! But for the final working soltion I spent another hour to get all use cases working. That's why I would like to share a code example which contains chained promises including an array of promises to wait for resolution.

Use case background is a server-side (nodeJs) file import after upload. I used promises in order to return an appropriate http status and result.

readFile: function (fileName) {
    if (fileName) {
        var deferred = Q.defer();
        var self = this;
        converter({input: fileName}, function (error, userData) {
            if (error) {
                deferred.reject(error);
            }
            self.storeUsers(error, userData)
                .then(function (success) {
                    if (success) {
                        deferred.resolve(success)
                    }
                })
                .fail(function (error) {                       
                    deferred.reject(error)                      
                });
        });
        return deferred.promise;
    }
},

storeUsers: function (error, data) {
    return Q.all(_.map(data, function (users, emailAddress) {
        var deferred = Q.defer();
        userRepository.findUserByEmail(emailAddress, function (user) {
            //...
            user.save(function (error) {
                if (error) {
                    deferred.reject(error);
                } else {
                    deferred.resolve(emailAddress);
                }
            });

        });
        return deferred.promise;
    }));
}

Hope that helps too!

Cheers Ben

Erastatus answered 18/12, 2014 at 17:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.