MongoDB和Node js异步编程

时间:2013-09-27 05:10:41

标签: javascript node.js mongodb asynchronous

我正在尝试解决考试问题,因此我无法按原样发布考试代码。所以我简化了它,它解决了我不理解的核心概念。基本上,我不知道如何减慢节点的异步执行速度,以便我的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 个答案:

答案 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条记录。相反,您可能想要对它们进行分页。