我在循环中进行多个mongoDB查询。并且希望将所有结果作为一个数据数组发送。但是,当我简单地使用return来发送数据时,它只是返回未定义的数据,而不等待所有DB请求的结果。我也试着使用q.modele,但问题是一样的。
代码:
var getPrayerInCat = function(data){
var result ;
var finalData = [];
if(data.length >0){
data.forEach(function(data2){
var id= data2.id;
Prayer.find({prayerCat:id},function(err,prayer){
var deferred = Q.defer()
if (err) { // ...
console.log('An error has occurred');
// res.send(err);
result= finalData = err
} else {
if(!prayer){
// console.log(data2.id+'--0');
data2.prayersCount = 0;
result = deferred.resolve(finalData.push(data2))
} else {
// console.log(data2.id+'--'+prayer.length);
data2.prayersCount = prayer.length;
// console.log(prayer)
result = deferred.resolve(finalData.push(data2))
} // else for data forward
}
deferred.promise;
})
// deferred.resolve(finalData);
})
/*if(finalData.length > 0) { return finalData;}*/
}
}
finalData返回时未定义。
让我们从使用promise的一般规则开始:
执行异步操作的每个函数都必须返回promise
在您的情况下,这些功能是什么?它是getPrayerInCat
、forEach
回调和Prayer.find
。
嗯,Prayer.find
不返回promise,它是一个库函数,所以我们不能修改它
为每个没有的函数创建一个即时包装器
在我们的例子中,使用Q的节点接口助手很容易:
var find = Q.nbind(Prayer.find, Prayer);
现在我们只有承诺,不需要再拖延了。第三条规则开始发挥作用:
所有使用异步结果执行操作的东西都会进入
.then
回调
…并返回结果。见鬼,如果"某事"是异步的,那么结果甚至可以是一个承诺!有了这个,我们可以编写完整的回调函数:
function getPrayerCount(data2) {
var id = data2.id;
return find({prayerCat:id})
// ^^^^^^ Rule 1
.then(function(prayer) {
// ^^^^^ Rule 3
if (!prayer)
data2.prayersCount = 0;
else
data2.prayersCount = prayer.length;
return data2;
// ^^^^^^ Rule 3b
});
}
现在,我们有一个更复杂的东西:一个循环。反复调用getPrayerCount()
会得到多个promise,它们的异步任务并行运行,并以未知的顺序解决。我们希望等待所有的任务,即在每个任务完成后得到一个解决所有结果的承诺。
对于如此复杂的任务,不要试图想出自己的解决方案:
检查库的API
在那里我们找到了Q.all
,它正是这样做的。编写getPrayerInCat
现在轻而易举:
function getPrayerInCat(data) {
var promises = data.map(getPrayerCount); // don't use forEach, we get something back
return Q.all(promises);
// ^^^^^^ Rule 1
}
如果我们需要对Q.all
解析到的数组执行任何操作,只需应用规则3。