Javascript如何在for循环完成后执行代码

Javascript如何在for循环完成后执行代码,javascript,node.js,asynchronous,Javascript,Node.js,Asynchronous,我正在尝试处理这个js/async场景,我正在尝试了解js世界的其他人是如何处理这个问题的 function doStuff(callback) { cursor.each(function(err, blahblah) { ...doing stuff here takes some time }); ... Execute this code ONLY after the `cursor.each` loop is finished callback(); 编辑

我正在尝试处理这个js/async场景,我正在尝试了解js世界的其他人是如何处理这个问题的

function doStuff(callback) {

  cursor.each(function(err, blahblah) {
    ...doing stuff here takes some time
  });

  ... Execute this code ONLY after the `cursor.each` loop is finished
  callback();
编辑

下面是一个更具体的例子,它使用了下面的大多数建议进行了更新,但仍然不起作用

function doStuff(callback) {

  MongoClient.connect(constants.mongoUrl, function(err, db) {

    var collection = db.collection('cases2');
    var cursor = collection.find();

    var promises = [];  // array for storing promises

    cursor.each(function(err, item) {

      console.log('inside each'); // NEVER GETS LOGGED UNLESS I COMMENT OUT THIS LINE: return Q.all(promises).then(callback(null, items));

      var def = Q.defer();        // Create deferred object and store
      promises.push(def.promise); // Its promise in the array

      if(item == null) {
        return def.resolve();
      }

      def.resolve();  // resolve the promise
    });

    console.log('items'); // ALWAYS GETS CALLED
    console.log(items);

    // IF I COMMENT THIS LINE OUT COMPLETELY, 
    // THE LOG STATEMENT INSIDE CURSOR.EACH ACTUALLY GETS LOGGED
    return Q.all(promises).then(callback(null, items));
  });
}

在不知道您在
游标中进行的异步调用的详细信息的情况下。每个
循环,我假设您都能够在每次调用的函数完成异步任务时调用回调:

function doStuff() {
    var promises = [];  // array for storing promises

    cursor.each(function(err, blahblah) {
        var def = Q.defer();        // create deferred object and store
        promises.push(def.promise); // its promise in the array

        call_async_function(..., def.resolve);  // resolve the promise in the async function's callback
    });

    // pass the array to Q.all, only when all are resolved will "callback" be called
    return Q.all(promises);
} 
然后,用法变成:

doStuff().then(callback)
请注意,回调调用现在从不涉及
doStuff
函数-该函数现在还返回承诺。您现在可以注册多个回调、失败回调等,而无需修改
doStuff
。这被称为“关注点分离”

[注:以上所有内容均基于Q promises库-


EDIT进一步的讨论和实验已经确定
。每个
调用本身都是异步的,并且在看到最后一行时不会向外部提供任何指示。我创建了一个示例来演示此问题的解决方案。

但不知道在
中进行的异步调用的详细信息>游标。每个
循环,我假设您能够在每次调用的函数完成异步任务时调用回调:

function doStuff() {
    var promises = [];  // array for storing promises

    cursor.each(function(err, blahblah) {
        var def = Q.defer();        // create deferred object and store
        promises.push(def.promise); // its promise in the array

        call_async_function(..., def.resolve);  // resolve the promise in the async function's callback
    });

    // pass the array to Q.all, only when all are resolved will "callback" be called
    return Q.all(promises);
} 
然后,用法变成:

doStuff().then(callback)
请注意,回调调用现在从未触及
doStuff
函数-该函数现在还返回承诺。您现在可以注册多个回调、失败回调等,而无需修改
doStuff
。这称为“关注点分离”

[注:以上所有内容均基于Q promises库-


编辑进一步的讨论和实验已经确定,
调用本身是异步的,并且在看到最后一行时不会向外部发出指示。我创建了一个示例,演示了此问题的解决方法。

无需使用承诺或任何其他依赖项/库,您只需

function doStuff(callback) {
添加计数器

    var cursor = new Array(); // init with some array data
    var cursorTasks = cursor.length;

    function cursorTaskComplete()
    {
        cursorTasks--;

        if ( cursorTasks <= 0 ) {
            // this gets get called after each task reported to be complete
            callback();
        }
    }

    for ( var i = 0; i < cursor.length; i++ ) {
        ...doing stuff here takes some time and does some async stuff

不使用承诺或任何其他依赖项/库,您可以

function doStuff(callback) {
添加计数器

    var cursor = new Array(); // init with some array data
    var cursorTasks = cursor.length;

    function cursorTaskComplete()
    {
        cursorTasks--;

        if ( cursorTasks <= 0 ) {
            // this gets get called after each task reported to be complete
            callback();
        }
    }

    for ( var i = 0; i < cursor.length; i++ ) {
        ...doing stuff here takes some time and does some async stuff

在我看来,一个优雅/理想的解决方案是

 cursor.each(........).then( function() { ....your stuff});
但如果没有这些,你可以做到这一点

要点如下所示……注意……什么时候

var doStuff = function(callback) {
      cursor.forEach(function(cursorStep) {
        var deferred = $q.defer();
        var promise = deferred.promise;
        allMyAsyncPromises.push(promise);
        cursorStep.execFn(cursorStep.stepMeta);
        promise.resolve;
      });

      $q.when(allMyAsyncPromises).then(callback);
}
在点击开始按钮等待几秒钟后…异步任务已被模拟为在5秒钟内完成,因此状态将相应更新


无法访问真正的游标对象..我不得不使用伪游标和数组。

在我看来,一个优雅/理想的解决方案是使用

 cursor.each(........).then( function() { ....your stuff});
但如果没有这些,你可以做到这一点

要点如下所示……注意……什么时候

var doStuff = function(callback) {
      cursor.forEach(function(cursorStep) {
        var deferred = $q.defer();
        var promise = deferred.promise;
        allMyAsyncPromises.push(promise);
        cursorStep.execFn(cursorStep.stepMeta);
        promise.resolve;
      });

      $q.when(allMyAsyncPromises).then(callback);
}
在点击开始按钮等待几秒钟后…异步任务已被模拟为在5秒钟内完成,因此状态将相应更新


无法访问真正的游标对象。我不得不使用伪游标和数组。

如果您想使用异步模块,可以使用async forEachSeries函数

代码段:

function doStuff(callback) {

  async.forEachSeries(cursor, function(cursorSingleObj,callbackFromForEach){
      //...do stuff which takes time
      //this callback is to tell when everything gets over execute the next function
      callbackFromForEach();
  },function(){
     //over here the execution of forEach gets over and then the main callback is called
    callback();
  });
}

如果要使用异步模块执行此操作,可以使用async forEachSeries函数

代码段:

function doStuff(callback) {

  async.forEachSeries(cursor, function(cursorSingleObj,callbackFromForEach){
      //...do stuff which takes time
      //this callback is to tell when everything gets over execute the next function
      callbackFromForEach();
  },function(){
     //over here the execution of forEach gets over and then the main callback is called
    callback();
  });
}

承诺,承诺…@VivinPaliath我认为这一部分无关紧要。我只是循环遍历blah的值并将其推送到一个数组。可能会有帮助:我如何知道何时处于
光标的最后一个元素。每个
。我可以告诉@Catfish我在这里看到的没有索引参数——关于如何等待多个异步事件的大量示例在继续之前完成。我假定您在
游标内调用的异步Mongo API。每个
也都有能力在每个单独操作结束时调用回调?承诺,承诺…@vivinvaliath我认为这一部分无关紧要。我只需循环blah的值并推送到一个数组。可能会有帮助:我如何知道恩,我在
游标的最后一个元素。每个
。我可以告诉@Catfish我在这里看到的没有索引参数——关于如何在继续之前等待多个异步操作完成的大量示例。我假设您在
游标中调用的异步Mongo API。每个
也都有在最后调用回调的能力每一个单独的动作?抱歉,我想我并没有在
游标中实际执行异步操作。每一个
循环。它只是游标。在回调方法之前没有完成的每个循环。不确定这是否会影响您的答案。这似乎不起作用。
返回Q.all(承诺)。然后(回调);
仍在执行
游标中的任何内容之前执行。每个都是执行的
。我认为问题是,点击
游标的回调需要一段时间。每个
所以
返回Q.all(承诺)。然后(回调)
游标之前执行。每个
承诺都是一个空数组,所以它只是启动回调。我不知道如何通过承诺来避免这种情况。不,理论上
承诺
数组已经满了(因为
。每个
都不是异步的)当调用
Q.all
时。@Catfish re:您的第一条注释-如果
光标中没有异步代码。每个
循环都会运行您的原始代码。re:您的第二条注释-是的,这就是承诺的工作方式。
Q.all
。然后
函数本身是异步的-它们会立即返回。哟你不能在JS中“忙-闲”,所以你必须有某种机制,不仅要等待异步内容完成,还要等待
doStuff
完成。承诺提供了这一点。抱歉,我猜我在
游标中没有实际做异步内容。每个
循环。它只是游标。每个循环