Javascript how to execute code after for loop completes
我正在尝试解决这个js /异步场景,我想知道js世界的其余部分如何处理这个问题。
1 2 3 4 5 6 7 8 | 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(); |
编辑
这是一个更具体的例子,使用下面的大多数建议进行了更新,但仍然无效。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 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)); }); } |
你可以简单地使用promises或任何其他依赖/库
1 | function doStuff(callback) { |
加一个柜台
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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 |
检查每个异步请求后
1 2 3 4 | ...when async operation is complete call cursorTaskComplete() } } |
在不知道您在
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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); } |
然后用法变为:
1 | doStuff().then(callback) |
注意回调的调用现在永远不会触及
[注意:所有以上基于Q promises库 - https://github.com/kriskowal/q]
编辑进一步的讨论和实验已经确定
如果要使用async模块执行此操作,可以使用async forEachSeries函数
代码段:
1 2 3 4 5 6 7 8 9 10 11 | 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(); }); } |
在我看来,优雅/理想的解决方案就是拥有类似的东西
1 | cursor.each(........).then( function() { ....your stuff}); |
但没有它,你可以做到这一点....更新
http://plnkr.co/edit/27l7t5VLszBIW9eFW4Ip?p=preview
这个的要点如下所示......注意......当
1 2 3 4 5 6 7 8 9 10 11 | 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秒内完成,因此状态将相应更新。
无法访问真正的光标对象..我不得不求助于虚拟光标和数组。