Rut*_*rns 2 javascript foreach mongoose node.js npm
我有点问题。这是代码:
情况一:
var foundRiders = [];
riders.forEach(function(rider){
Rider.findOne({_id: rider}, function(err, foundRider){
if(err){
console.log("program tried to look up rider for the forEach loop finalizing the results, but could not find");
} else {
foundRiders.push(foundRider);
console.log(foundRiders);
}
});
});
Run Code Online (Sandbox Code Playgroud)
情况B
var foundRiders = [];
riders.forEach(function(rider){
Rider.findOne({_id: rider}, function(err, foundRider){
if(err){
console.log("program tried to look up rider for the forEach loop finalizing the results, but could not find");
} else {
foundRiders.push(foundRider);
}
});
});
console.log(foundRiders);
Run Code Online (Sandbox Code Playgroud)
因此,在情况 A 中,当我控制台日志时,我发现 foundRiders 是一个充满对象的数组。在情况 B 中,当我将 console.log 放在循环之外时,我的 roundRiders 数组完全为空...
怎么来的?
正如其他人所说,您的数据库代码是异步的。这意味着你的循环内的回调会在稍后的某个时间被调用,在你的循环已经完成很久之后。有多种方法可以为异步循环编程。在您的情况下,最好转到数据库的承诺接口,然后开始使用承诺来协调您的多个数据库调用。你可以这样做:
Promise.all(riders.map(rider => {
return Rider.findOne({_id: rider}).exec();
})).then(foundRiders => {
// all found riders here
}).catch(err => {
// error here
});
Run Code Online (Sandbox Code Playgroud)
这使用.exec()mongoose 数据库的接口来运行您的查询并返回一个承诺。然后,riders.map() builds and returns an array of these promises. Then,Promise.all() monitors all the promises in the array and calls。那么()when they are all done or.catch()`当有错误。
如果您想忽略数据库中未找到的任何骑手,而不是因错误而中止,则可以执行以下操作:
Promise.all(riders.map(rider => {
return Rider.findOne({_id: rider}).exec().catch(err => {
// convert error to null result in resolved array
return null;
});
})).then(foundRiders => {
foundRiders = foundRiders.filter(rider => rider !== null);
console.log(founderRiders);
}).catch(err => {
// handle error here
});
Run Code Online (Sandbox Code Playgroud)
为了帮助说明这里发生了什么,这是一种更老式的监视方式,当所有数据库回调都完成时(使用手动计数器):
riders.forEach(function(rider){
let cntr = 0;
Rider.findOne({_id: rider}, function(err, foundRider){
++cntr;
if(err){
console.log("program tried to look up rider for the forEach loop finalizing the results, but could not find");
} else {
foundRiders.push(foundRider);
}
// if all DB requests are done here
if (cntr === riders.length) {
// put code here that wants to process the finished foundRiders
console.log(foundRiders);
}
});
});
Run Code Online (Sandbox Code Playgroud)
维护计数器以跟踪多个异步请求的业务是Promise.all()内置的。
上面的代码假设您希望并行化代码并一起运行查询以节省时间。如果你想序列化你的查询,那么你可以await在 ES6 中使用一个for循环来使循环“等待”每个结果(这可能会减慢速度)。以下是你将如何做到这一点:
async function lookForRiders(riders) {
let foundRiders = [];
for (let rider of riders) {
try {
let found = await Rider.findOne({_id: rider}).exec();
foundRiders.push(found);
} catch(e) {
console.log(`did not find rider ${rider} in database`);
}
}
console.log(foundRiders);
return foundRiders;
}
lookForRiders(riders).then(foundRiders => {
// process results here
}).catch(err => {
// process error here
});
Run Code Online (Sandbox Code Playgroud)
请注意,虽然这看起来像是您在其他语言中可能习惯的更同步的代码,但它仍然使用异步概念,并且该lookForRiders()函数仍然返回一个承诺,您可以使用.then(). 这是 Javascript 中的一个新功能,它使某些类型的异步代码更易于编写。
| 归档时间: |
|
| 查看次数: |
5193 次 |
| 最近记录: |