我正在尝试解决这个js /异步场景,我试图了解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));
});
}
答案 0 :(得分:4)
不使用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
检查每个异步请求后
...when async operation is complete call
cursorTaskComplete()
}
}
答案 1 :(得分:2)
在不知道您在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);
}
然后用法变为:
doStuff().then(callback)
注意回调的调用现在永远不会触及doStuff
函数 - 该函数现在也返回一个promise。您现在可以注册多个回调,故障回调等,而无需修改doStuff
。这被称为“关注点分离”。
[注意:所有上述内容均基于Q promises库 - https://github.com/kriskowal/q]
编辑进一步的讨论和实验已经确定.each
调用本身是异步的,并且在看到最后一行时没有给出外部指示。我创建了Gist来演示解决此问题的方法。
答案 2 :(得分:0)
在我看来,优雅/理想的解决方案就是拥有像
这样的东西 cursor.each(........).then( function() { ....your stuff});
但没有它,你可以做到这一点....更新
http://plnkr.co/edit/27l7t5VLszBIW9eFW4Ip?p=preview
这个要点如下所示......注意......当
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秒内完成,因此状态将相应更新。
无法访问真正的光标对象。我不得不使用虚拟光标和数组。
答案 3 :(得分:0)
如果你想用异步模块做,你可以使用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();
});
}