Reputation: 343
So I realized today I've been iterating through promises badly by using recursion and nested promises and wanted to learn how to use Q.all()
correctly. I am trying to iterate through a series of async functions and waiting for all of them to resolve before continuing. In this current implementation, Q.all is returned immediately without waiting for the promises to resolve. Here is my code for the iterating function
var updateNewReleasePlaylists = function () {
var self = this;
var promises = [];
var deferred = Q.defer();
// query for all users who have new releases
User.find({
$and: [{
'new_releases': {
$exists: true,
$ne: []
}
},
{
'refresh_token': {
$exists: true
}
}
]
}, 'new_releases',
function (err, users) {
if (err) {
throw new Error(err);
}
for (var i = 0; i < users.length; i++) {
console.log('when?')
promises.push(updatePlaylist(users[i]));
}
});
return Q.all(promises);
}
and the here is the async function it is calling:
function updatePlaylist(user) {
var deferred = Q.defer();
User.findOne({'_id': user._id}, function(err, user) {
if (err) {
deferred.reject(err);
}
console.log(user);
deferred.resolve();
})
return deferred.promise;
}
If I change the implementation like so it works totally fine:
var updateNewReleasePlaylists = function () {
var self = this;
var promises = [];
var deferred = Q.defer();
// query for all users who have new releases
User.find({
$and: [{
'new_releases': {
$exists: true,
$ne: []
}
},
{
'refresh_token': {
$exists: true
}
}
]
}, 'new_releases',
function (err, users) {
if (err) {
throw new Error(err);
}
for (var i = 0; i < users.length; i++) {
console.log('when?')
promises.push(updatePlaylist(users[i]));
}
deferred.resolve(Q.all(promises)); // DIFFERENT
});
return deferred.promise; // DIFFERENT
}
From what I can tell, this is an incorrect way of implementing this however and I would like to get it right the first time. If it's any help, here is where I'm calling the updateNewReleasePlaylists
function for testing.
it('updateNewReleasePlaylists should properly resolve after all users playlists have been updated', function (done) {
this.timeout(60000);
testHelper.stageSpotifyUser(20)
.then(testHelper.stageSpotifyUser(20))
.then(testHelper.stageSpotifyUser(20))
.then(function () {
playlist.updateNewReleasePlaylists()
.then(function (promises) {
console.log(promises.length);
console.log('should be after');
done();
})
})
})
Thanks for your help ahead of time.
Upvotes: 0
Views: 704
Reputation: 1210
If the promises array is empty then it seems right to get your return, because there is nothing to wait for. When find() is completed, due to its async nature, promises array is still empty, since the function (err, users) has not been invoked yet.
So, if I am right about find() being async, you should return the whole User.find() or promise-wrap if needed and return that.
Upvotes: 1