简体   繁体   English

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

[英]Javascript how to execute code after for loop completes

I'm trying to work through this js/async scenario and i'm trying to know how the rest of the js world handles this. 我正在尝试解决这个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();

EDIT 编辑

Here's a more concrete example updated using most of the suggestions below which still doesn't work. 这是一个更具体的示例,使用下面的大多数建议进行了更新,但仍然无法使用。

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));
  });
}

without using promises or any other dependencies/libraries you can simply 无需使用Promise或任何其他依赖项/库,您只需

function doStuff(callback) {

add a counter 添加一个柜台

    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

check after each async request 在每个异步请求之后检查

        ...when async operation is complete call
        cursorTaskComplete()
  }
}

Without knowing the details of the async calls you're making within the cursor.each loop, I shall assume that you have the ability to invoke a callback each time the functions invoked therein have completed their async task: 在不知道您在cursor.each循环中进行异步调用的详细信息的情况下,我将假定您有能力在每次调用的回调函数完成其异步任务时调用回调:

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);
} 

and the usage then becomes: 用法变为:

doStuff().then(callback)

Note how the invocation of the callback now never touches the doStuff function - that function now also returns a promise. 请注意,回调的调用现在永远不会触及doStuff函数-该函数现在还返回一个promise。 You can now register multiple callbacks, failure callbacks, etc, all without modifying doStuff . 您现在可以注册多个回调,失败回调等,而无需修改doStuff This is called "separation of concerns". 这称为“关注点分离”。

[NB: all the above based on the Q promises library - https://github.com/kriskowal/q] [NB:以上所有基于Q promises库-https: //github.com/kriskowal/q]

EDIT further discussion and experimentation has determined that the .each call is itself async, and gives no indication to the outside when the last row has been seen. EDIT的进一步讨论和实验已经确定.each调用本身是异步的,并且在看到最后一行时不向外界发出任何指示。 I've created a Gist that demonstrates a resolution to this problem. 我创建了一个Gist ,它可以解决这个问题。

if you want to do it with the async module, you can make use of the async forEachSeries function 如果要使用async模块执行此操作,则可以使用async forEachSeries函数

Code snippet: 程式码片段:

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();
  });
}

In my mind an elegant/ideal solution would be to have something like 在我看来,一个优雅/理想的解决方案是

 cursor.each(........).then( function() { ....your stuff});

But without that you can do this....UPDATED 但是没有那个,你可以做到这一点。

http://plnkr.co/edit/27l7t5VLszBIW9eFW4Ip?p=preview http://plnkr.co/edit/27l7t5VLszBIW9eFW4Ip?p=预览

The gist of this is as shown below...notice....when 其要旨如下所示。

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);
}

After hitting the start button wait for few seconds...the async tasks have been simulated to finish in 5 seconds so the status will update accordingly. 按下开始按钮后,等待几秒钟...异步任务已模拟为在5秒钟内完成,因此状态将相应更新。

Not having access to a real cursor object..I had to resort of fake cursor like and array. 无法访问真实的游标对象。.我不得不诉诸伪造的游标,如和数组。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM