javascript 正确使用异步(使用 forEach)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20632338/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
using async correctly (with forEach)
提问by gadu
So I have a nice chunk of nested async code running together and it all seems to be okay, except for when I get to the end of it. my last function in a series block is a forEach: that then goes into a async.parallel
所以我有一个很好的嵌套异步代码块一起运行,一切似乎都很好,除了当我到达它的末尾时。我在系列块中的最后一个函数是一个 forEach:然后进入 async.parallel
Managed to track down the following chunk which does not run in order:
设法追踪以下未按顺序运行的块:
async.forEach(array, function(elem, callback) {
async.parallel([
function(callback) {
database-call-A(elem, unction(err, data) {
if(err){
console.log("error on first parallel");
callback({err: false}); // will break out
} else {
elem.c = data;
callback();
}
});
},
function(callback) {
database-call-B(elem, function(err, data) {
if(err){
console.log("error on first parallel");
callback({err: false}); // will break out
} else {
elem.c = data;
callback();
}
});
}
]); // end async.parallel
// if forEach needs a callback after every iteration (which I think it does?)
console.log("PRINTS N TIMES - ONCE FOR EVERY ITERATION");
callback(); // both parallel functions have run, call back forEach
}); // end forEach
console.log("Donions - prints when finished");
When I tested this code by throwing print statements everywhere, I noticed that "PRINTS N TIMES ..." ran N times, then I got "Donions .." and THEN my do something(); and other stuff(); started getting called in my async.parallel.
当我通过到处抛出打印语句来测试这段代码时,我注意到“PRINTS N TIMES ...”运行了 N 次,然后我得到了“Donions ..”然后我做某事();和其他东西();开始在我的 async.parallel 中被调用。
Why is my forEach iterating through without waiting for the callbacks from async.parallel?
为什么我的 forEach 会在不等待 async.parallel 回调的情况下进行迭代?
回答by jeremija
First, there is no async.forEach
, but there is the async.each
function. The async.parallel
function will execute all tasks simoultaneously and then execute the callback if it was defined.
首先,没有async.forEach
,但有async.each
功能。该async.parallel
函数将同时执行所有任务,然后执行回调(如果已定义)。
In your source, the callback
function will be executed as soon as the async.parallel
is executed, not after all of it's functions have returned. I suggest you read the documentation.
在您的源代码中,该callback
函数将在执行后立即async.parallel
执行,而不是在所有函数都返回后执行。我建议你阅读文档。
If you want to execute the callback
after all the parallel functions' callbacks have been called, you should pass the forEach
's callback to the async.parallel
function as a second parameter, after the array of functions. Also, you should probably pass the callbacks to both databaseCallA
and databaseCallB
thus making them call their callbacks when they finish so they aren't executed prematurely.
如果要在调用callback
所有并行函数的回调之后执行,则应将forEach
的回调作为async.parallel
函数数组之后的第二个参数传递给函数。此外,您可能应该将回调传递给两者databaseCallA
,databaseCallB
从而使它们在完成时调用它们的回调,这样它们就不会过早执行。
async.each(array, function(elem, callback) {
async.parallel([
function(cb) {
databaseCallA(cb);
// if you have called the cb here, the `async.parallel` function would "think" that the databaseCallA has finished, even though it may not have started yet.
},
function(cb) {
databaseCallB(cb):
}
], callback);
});
You should modify your database call functions to accept the callback argument and make them call the callback after they have done their work.
您应该修改数据库调用函数以接受回调参数,并让它们在完成工作后调用回调。
The point of async calls is to free the resources for other jobs while waiting for your job to finish - your code will continue it's execution, but you can use the callbacks or some kind of event-based notifications to notify others your async job has finished.
异步调用的目的是在等待您的工作完成时释放其他工作的资源 - 您的代码将继续执行,但您可以使用回调或某种基于事件的通知来通知其他人您的异步工作已完成.
EDIT
编辑
To execute something after all parallel calls have finished:
在所有并行调用完成后执行某些操作:
async.each(array, function(elem, callback) {
async.parallel([
function(cb) {
// I use the setTimeout function to intentionally
// delay the response
setTimeout(function() {
// the first cb parameter is error, the second is result
// in case there was no error
cb(undefined, 'a');
}, 500);
},
function(cb) {
setTimeout(function() {
cb(undefined, 'b');
}, 300);
},
function(cb) {
setTimeout(function() {
cb(undefined, 'c');
}, 800);
}
], function(err, results) {
// this will be executed only after all three cb's are executed. In
// this case, after about 800ms. The results variable will be an
// array containing the resuts passed to each cb. In this case it
// will be ['a', 'b', 'c'].
// you could call the main callback here
callback();
});
}, function(err) {
// this callback will be executed either after everything was done,
// or if an error has occurred.
if (err) {
handleError(err);
return;
}
// this should be executed after all `each` and `parallel` calls
// have finished. In this case, it should also be after about 800ms
// from the start, since everything was executed in parallel
console.log('finished');
// now you are sure everything was done, do something afterwards
after();
});
// this will be executed immediately so don't put anything here
// that depends on the outcome of the async calls above
console.log('test');
回答by Sayris
I'm not sure for this answer, but according with async documentation, I think you must do this :
我不确定这个答案,但根据异步文档,我认为你必须这样做:
async.forEach(array, function(elem, callback) {
async.parallel([
function(callback) {
database-call-A();
callback();
},
function(callback) {
database-call-B():
callback(); // callback for second parallel function
}
], function(err,result) {
// this code is executed when paralles functions ends
console.log("PRINTS N TIMES - ONCE FOR EVERY ITERATION");
callback();
}); // end async.parallel
}); // end forEach
regards.
问候。