2

我正在尝试解决考试问题,因此无法按原样发布考试代码。因此,我进行了简化,以解决我不理解的核心概念。基本上,我不知道如何减慢节点的异步执行速度,以便我的 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 不等待回调完成。如何修改代码,以便在计算数组中不符合查询条件的图像数量之前完成回调的执行?

在此先感谢您的时间。

巴拉特

4

4 回答 4

2

我假设您想做 100000 次并行数据库调用。为了在每个调用回调中“等待”10000 个调用完成,我们增加完成调用计数器并在最后一个调用完成时调用主回调。请注意,这里非常常见的错误是将 for 循环变量用作回调内部的闭包。这不会像预期的那样工作,因为首先调度的所有 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);
 });
于 2013-09-27T07:26:39.903 回答
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 设计者不想给程序员的一种能力(虽然不太清楚为什么)。

于 2013-09-27T05:33:03.217 回答
0

你不需要放慢任何速度。如果您只是尝试从相册集合中加载 100,000 张图像,您可以考虑使用异步框架。这将允许您分配任务,直到作业完成。

此外,您可能不希望一个接一个地请求 100,000 条记录。相反,您可能想要对它们进行分页。

于 2013-09-27T05:18:53.987 回答
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);
    });
于 2013-09-27T05:18:10.057 回答