Javascript/NodeJS:在forEach循环中推送值后数组为空
我有点小问题。代码如下: 情景A:Javascript/NodeJS:在forEach循环中推送值后数组为空,javascript,node.js,mongoose,npm,foreach,Javascript,Node.js,Mongoose,Npm,Foreach,我有点小问题。代码如下: 情景A: var foundRiders = []; riders.forEach(function(rider){ Rider.findOne({_id: rider}, function(err, foundRider){ if(err){ console.log("program tried to look up rid
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);
}
});
});
情况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);
所以在一个控制台日志中,我得到foundRiders是一个充满对象的数组。在情况B中,当我将console.log放在循环外时,我的roundRiders数组完全为空
为什么呢?正如其他人所说,您的数据库代码是异步的。这意味着您的循环中的回调将在稍后的某个时间调用,而这是在您的循环已经完成很久之后。为异步循环编程有多种方法。在您的情况下,最好转到数据库的promise接口,然后开始使用promises来协调多个数据库调用。您可以这样做:
Promise.all(riders.map(rider => {
return Rider.findOne({_id: rider}).exec();
})).then(foundRiders => {
// all found riders here
}).catch(err => {
// error here
});
这将使用mongoose数据库的.exec()
接口运行查询并返回承诺。然后,riders.map()构建并返回这些承诺的数组。然后,
Promise.all()监视数组中的所有承诺,并在它们全部完成时调用
.Then(),或者在出现错误时调用
.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
});
为了帮助说明这里发生了什么,这是一种更老式的监视所有数据库回调完成的方式(使用手动计数器): 维护计数器以跟踪多个异步请求是
Promise.all()
内置的功能
上面的代码假设您希望并行化代码并一起运行查询以节省时间。如果您想序列化查询,那么您可以在ES6中使用
wait
和for
循环,使循环对每个结果“wait”(这可能会减慢速度)。以下是您将如何做到这一点:
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
});
请注意,虽然这看起来更像是在其他语言中使用的同步代码,但它仍然使用异步概念,
lookForRiders()
函数仍然返回一个承诺,您可以使用访问谁的结果。then()
。这是Javascript中较新的功能,使某些类型的异步代码更易于编写。它是异步的,在查询完成之前会调用console.log。这就是为什么要传递回调函数console.log(foundRiders)代码>在附加字符之前执行。findOne
由于是异步的,所以执行起来很精细……。因为为什么不呢!而且nodejs是异步的,我如何延迟它?我来自PHP,这个异步编程需要一些时间来掌握。非常好的答案!不幸的是,这是他们在完整的webdeveloper课程中没有教授的内容。我想我必须继续使用advanced web developer one。@RutgerBrns-因为看起来您可能对堆栈溢出相当陌生,如果这回答了您的问题,那么您可以通过单击答案左侧的复选标记向社区指出这一点。这将“接受”这个答案,并为您在堆栈溢出上赢得一些声誉点数,因为您遵循了这里的正确过程。
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
});