Reputation: 355
I have a method (see code example) and I'm trying to return a promises list to parent method. My problem is when pushing promises in my promiseList array.
getDistance is a method returning a Promise. If I do .then() in getDistance method,everything is OK. Nevertheless, if I try to push the promise into my array, when I do .then in parent method, it is empty.
I think it may happen due to each loop is asynchronous...
var promiseList = [];
res = db.collection.find query statement...
res.each(function(err, doc) {
if (doc!==null) {
promiseList.push(
getDistance(orgLat, orgLon, destLat, desLon)
);
}
});
return Promise.all(promTimeList);
I'm using MongoDB as database, and NodeJS in server side, with mongodb as driver to connecto to my database and Bluebird as library to implement promises.
Thanks in advance!
Upvotes: 1
Views: 1302
Reputation: 8718
Iterate the collection syncrhonously by using await
with cursor.next()
in a while
loop:
var cursor = db.collection.find({});
while ((doc = await cursor.next()) != null) {
promiseList.push(
getDistance(doc.orgLat, doc.orgLon, doc.destLat, doc.desLon);
);
}
Upvotes: 1
Reputation: 3501
I think you are correct in that the issue is due to the fact that each
is asynchronous. You can use defer
to wrap callback APIs (like each
) into promises. It would work something like this:
res = db.collection.find query statement...
processResponse(res)
.then(function(promiseList) {
// execute all the promises
return Promise.all(promiseList);
}, function (err) {
// handle error
});
function processResponse(res) {
var deferred = Promise.pending();
var promiseList = [];
res.each(function(err, doc) {
if (err) {
// error, abort
deferred.reject(err);
return;
}
else if (doc != null) {
promiseList.push(
getDistance(orgLat, orgLon, destLat, desLon)
);
}
else {
// finished looping through all results, return the promise list
deferred.resolve(promiseList);
}
});
return deferred.promise;
}
See more on defer
with bluebird at the following link (look for "So when should deferred be used?"):
https://github.com/petkaantonov/bluebird/wiki/Promise-anti-patterns
Update: According to this post:
Define empty Bluebird promise like in Q
It looks like there is a Promise constructor that may be the preferred way to do this. The processResponse
method would look like this:
function processResponse(res) {
return new Promise(function(resolve, reject) {
var promiseList = [];
res.each(function(err, doc) {
if (err) {
// error, abort
reject(err);
return;
}
else if (doc != null) {
promiseList.push(
getDistance(orgLat, orgLon, destLat, desLon)
);
}
else {
// finished looping through all results, return the promise list
resolve(promiseList);
}
});
});
}
Thanks to @Bergi. Please correct me if I am wrong. I am more familiar with the Q library (https://github.com/kriskowal/q) than bluebird.
Upvotes: 1