MongoDB和Node js异步编程

MongoDB and Node js Asynchronous programming

本文关键字:异步 编程 js Node MongoDB      更新时间:2023-09-26

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

提前感谢您的时间。

巴拉特

我假设你想做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);
 });

我并不是说这是在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设计者不想提供给程序员的功能(虽然不知道为什么)。

因为你知道它不会等待呼叫回来。您可以在回调函数中执行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);
    });

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

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