在nodejs中,如何在mongodb调用返回之前停止FOR循环

Sil*_*ser 8 javascript mongodb node.js express

请查看下面的代码段.我有一个名为'stuObjList'的JSON对象数组.我想循环通过数组来查找具有特定标志集的特定JSON对象,然后进行数据库调用以检索更多数据.

当然,FOR循环不等待db调用返回并以j == length到达结尾.当db调用返回时,索引'j'超出了数组索引.我理解node.js是如何工作的,这是预期的行为.

我的问题是,这里的工作是什么.我怎样才能实现我想要实现的目标?谢谢, - su

...............
...............
...............
else
{
  console.log("stuObjList.length: " + stuObjList.length);
  var j = 0;
  for(j = 0; j < stuObjList.length; j++)
  {
    if(stuObjList[j]['honor_student'] != null)
    {     
      db.collection("students").findOne({'_id' : stuObjList[j]['_id'];}, function(err, origStuObj)
      {
        var marker = stuObjList[j]['_id'];
        var major = stuObjList[j]['major'];
      });
    }

    if(j == stuObjList.length)
    {
      process.nextTick(function()
      {
        callback(stuObjList);
      });
    }
  }
}
});
Run Code Online (Sandbox Code Playgroud)

Cli*_*ris 8

" async "是一个非常流行的模块,用于抽象异步循环并使代码更易于读取/维护.例如:

var async = require('async');

function getHonorStudentsFrom(stuObjList, callback) {

    var honorStudents = [];

    // The 'async.forEach()' function will call 'iteratorFcn' for each element in
    // stuObjList, passing a student object as the first param and a callback
    // function as the second param. Run the callback to indicate that you're
    // done working with the current student object. Anything you pass to done()
    // is interpreted as an error. In that scenario, the iterating will stop and
    // the error will be passed to the 'doneIteratingFcn' function defined below.
    var iteratorFcn = function(stuObj, done) {

        // If the current student object doesn't have the 'honor_student' property
        // then move on to the next iteration.
        if( !stuObj.honor_student ) {
            done();
            return; // The return statement ensures that no further code in this
                    // function is executed after the call to done(). This allows
                    // us to avoid writing an 'else' block.
        }

        db.collection("students").findOne({'_id' : stuObj._id}, function(err, honorStudent)
        {
            if(err) {
                done(err);
                return;
            }

            honorStudents.push(honorStudent);
            done();
            return;
        });
    };

    var doneIteratingFcn = function(err) {
        // In your 'callback' implementation, check to see if err is null/undefined
        // to know if something went wrong.
        callback(err, honorStudents);
    };

    // iteratorFcn will be called for each element in stuObjList.
    async.forEach(stuObjList, iteratorFcn, doneIteratingFcn);
}
Run Code Online (Sandbox Code Playgroud)

所以你可以像这样使用它:

getHonorStudentsFrom(studentObjs, function(err, honorStudents) {
    if(err) {
      // Handle the error
      return;
    }

    // Do something with honroStudents
});
Run Code Online (Sandbox Code Playgroud)

需要注意的是.forEach()将调用你的迭代函数在stuObjList每个元素"并联"(即,它不会等待一个迭代函数调用它的下一个数组元素之前完成被称为一个数组元素).这意味着您无法真正预测迭代器的功能 - 或者更重要的是数据库调用 - 的运行顺序.最终结果:不可预知的荣誉学生顺序.如果订单很重要,请使用.forEachSeries()函数.