function getBlocks(docs){
var jsonResults = docs;
for(var i = 0; i < jsonResults.length; i++){
console.log(jsonResults[i]); //Proper result
database.Block.findOne({brand_id: docs[i]._brand[0]['_id'], timestamp: {$lte: new Date()}}, function(error, results){
console.log(jsonResults[i]); //Undefined
console.log(i); //Returns 2 twice (there's 2 documents)
res.json(jsonResults);
});
}
}
我对NodeJS了解所以我知道它与NodeJS的异步性质有关,但我不知道如何修复它。
编辑:我已经更新了代码。我希望在forEach完成后输出更改的数组,并且我已经附加了数据。
function getBlocks(docs){
var jsonResults = docs;
jsonResults.forEach(function(doc, i){
console.log(doc);
database.Block.findOne({brand_id: docs[i]._brand[0]['_id'], timestamp: {$lte: new Date()}}, function(error, results){
jsonResults[i]['test'] = results;
console.log(jsonResults[i]['test']); //Has array test. Previous line worked.
});
});
res.json(jsonResults); //Outputs unchanged array.
}
答案 0 :(得分:1)
是的,这是一个经典的范围界定问题。调用findOne
内的回调时i
已经是数组的最后一个索引。但是函数创建了一个单独的范围(与代码块不同),所以试试这个:
function getBlocks(docs){
var jsonResults = docs;
jsonResults.forEach(function(doc, i) {
console.log(doc); //Proper result
database.Block.findOne({brand_id: doc._brand[0]['_id'], timestamp: {$lte: new Date()}}, function(error, results){
console.log(doc);
console.log(i);
res.json(jsonResults);
});
});
}
编辑另一个问题有点不同。这是一个同步的问题。您必须等到所有异步作业完成它们的操作然后继续。看看async.js。这是一个非常好的图书馆,可以帮助您以干净简单的方式实现这一目标。你可以在你的实现这个机制。尝试这样的事情:
function getBlocks(docs){
var jsonResults = docs,
jobs = [];
var finalize = function() {
// here goes the final code
res.json(jsonResults); //Outputs unchanged array.
};
jsonResults.forEach(function(doc, i){
jobs.push(i); // add current job to the pool
console.log(doc);
database.Block.findOne({brand_id: docs[i]._brand[0]['_id'], timestamp: {$lte: new Date()}}, function(error, results){
jsonResults[i]['test'] = results;
console.log(jsonResults[i]['test']); //Has array test. Previous line worked.
// remove current job from the pool
var idx = jobs.indexOf(i);
if (idx != -1) {
jobs.splice(idx, 1);
}
// if no more jobs then finalize
if (typeof jobs[0] === "undefined") {
finalize();
}
});
});
}