Javascript如何在for循环完成后执行代码
我正在尝试处理这个js/async场景,我正在尝试了解js世界的其他人是如何处理这个问题的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(); 编辑
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
完成。承诺提供了这一点。抱歉,我猜我在游标中没有实际做异步内容。每个循环。它只是游标。每个循环