$q promise with Underscore _each

2019-01-15 20:22发布

问题:

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.

回答1:

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);


回答2:

$q.all([promise1,promise2,promise3,etc])
.then(function(results){
   alert("This alert will happen after all promises are resolved.");
 })


回答3:

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