我正在尝试解决考试问题,因此我无法按原样发布考试代码。所以我简化了它,它解决了我不理解的核心概念。基本上,我不知道如何减慢节点的异步执行速度,以便我的mongo代码能够赶上它。这是代码:
MongoClient.connect('mongodb://localhost:27017/somedb', function(err, db) {
if (err) throw err;
var orphans = [];
for (var i; i < 100000; i++) {
var query = { 'images' : i };
db.collection('albums').findOne(query, function(err, doc_album) {
if(err) throw err;
if (doc_album === null) {
orphans.push(i);
}
});
}
console.dir(orphans.length);
return db.close();
});
所以我试图创建一个与我的查询条件不匹配的图像数组。我最终得到的orphans.length值为0,因为Node不等待回调完成。在计算数组中不符合我的查询条件的图像数量之前,如何修改代码以使回调完成执行?
提前感谢您的时间。
巴勒特
答案 0 :(得分:2)
我假设您要进行100000个并行数据库调用。要在每次调用回调中“等待”10000次调用完成,我们增加完成的调用计数器并在最后一次调用完成时调用主要回调。注意,这里非常常见的错误是将循环变量用作回调内的闭包。这不会像预期的那样工作,因为首先执行的所有10000个处理程序和首次执行的循环变量具有相同的最大值。
function getOrphans(cb) {
MongoClient.connect('mongodb://localhost:27017/somedb', function(err, db) {
if (err) cb(err);
var orphans = [];
var numResponses = 0;
var maxIndex = 100000
for (var i = 0; i < maxIndex; i++) {
// problem: by the time you get reply "i" would be 100000.
// closure variable changed to function argument:
(function(index) {
var query = { 'images' : index };
db.collection('albums').findOne(query, function(err, doc_album) {
numResponses++;
if(err) cb(err);
if (doc_album === null) {
orphans.push(index);
}
if (numResponses == maxIndex) {
db.close();
cb(null, orphans);
}
});
})(i); // this is "immediately executed function
}
});
}
getOrphans(function(err, o) {
if (err)
return console.log('error:', err);
console.log(o.length);
});
答案 1 :(得分:1)
我不是建议这是在Mongo中处理这个特定问题的最佳方法,但是如果你需要等待数据库回复才能继续,那么只需使用回调来启动下一个请求。
这一开始并不明显,但您可以参考函数本身内的结果处理函数:
var i = 0;
var mycback = function(err, doc_album) {
// ... process i-th result ...
if (++i < 100000) {
db.collections("album").findOne({'images': i}, mycback);
} else {
// request is complete, "return" result
result_cback(null, res);
}
};
db.collections('album').findOne({'images': 0}, mycback);
这也意味着您的函数本身将是异步的(即希望result_cback
参数使用结果调用而不是使用return
)。
编写一个调用异步函数的同步函数是不可能的。
你不能在Javascript中“等待”一个事件......你必须为结果设置一个处理程序然后终止。
通过编写“嵌套事件循环”,在基于事件的处理中等待事件,例如,在大多数GUI框架中如何处理消息框。这是Javascript设计人员不想给程序员的功能(虽然不确定原因)。
答案 2 :(得分:0)
因为你知道它不会等待电话回来。您可以在回调函数中执行console.dir
,这应该可行(尽管我还没有测试过)
db.collection('albums').findOne(query, function(err, doc_album) {
if(err) throw err;
if (doc_album === null) {
orphans.push(i);
}
console.dir(orphans.length);
});
答案 3 :(得分:0)
你不需要放慢速度。如果您只是尝试从相册集合中加载100,000个图像,则可以考虑使用async框架。这将允许您分配任务,直到作业完成。
此外,您可能不希望逐个请求100,000条记录。相反,您可能想要对它们进行分页。