Javascript 完成所有异步forEach回调后的回调
正如标题所示。我该怎么做 我想在forEach循环遍历每个元素并完成一些异步处理之后调用Javascript 完成所有异步forEach回调后的回调,javascript,node.js,asynchronous,callback,Javascript,Node.js,Asynchronous,Callback,正如标题所示。我该怎么做 我想在forEach循环遍历每个元素并完成一些异步处理之后调用whenaldone() [1, 2, 3].forEach( function(item, index, array, done) { asyncFunction(item, function itemDone() { console.log(item + " done"); done(); }); }, function allDone() {
whenaldone()
[1, 2, 3].forEach(
function(item, index, array, done) {
asyncFunction(item, function itemDone() {
console.log(item + " done");
done();
});
}, function allDone() {
console.log("All done");
whenAllDone();
}
);
能让它像这样工作吗?当forEach的第二个参数是一个回调函数时,它会在经过所有迭代后运行吗
预期产出:
3 done
1 done
2 done
All done!
迭代列表时不需要回调。只需在循环之后添加
end()
调用
posts.forEach(function(v, i){
res.write(v + ". Index " + i);
});
res.end();
Array.forEach
不提供这种精确性(如果可以的话),但有几种方法可以实现您想要的:
使用简单计数器
(感谢@vanuan和其他人)这种方法保证在调用“done”回调之前处理所有项。您需要使用在回调中更新的计数器。取决于索引参数的值,参数不提供相同的保证,因为异步操作的返回顺序不保证
使用ES6承诺
(promise库可用于较旧的浏览器):
问题的主体已被编辑,以删除先前同步的示例代码,因此我更新了我的答案以澄清问题。 原始示例使用类似同步的代码来建模异步行为,因此应用了以下内容:
array.forEach
和res.write
,因此您只需在调用forEach之后放置回调:
posts.foreach(function(v, i) {
res.write(v + ". index " + i);
});
res.end();
如果您遇到异步函数,并且希望确保在执行代码之前完成其任务,那么我们始终可以使用回调功能 例如:
var ctr = 0;
posts.forEach(function(element, index, array){
asynchronous(function(data){
ctr++;
if (ctr === array.length) {
functionAfterForEach();
}
})
});
注意:
functionAfterForEach
是foreach任务完成后要执行的函数asynchronous
是在foreach内部执行的异步函数。这是Node.js的异步解决方案
使用异步npm包
希望这能解决您的问题,我通常在需要使用内部异步任务执行forEach时使用它
foo = [a,b,c,d];
waiting = foo.length;
foo.forEach(function(entry){
doAsynchronousFunction(entry,finish) //call finish after each entry
}
function finish(){
waiting--;
if (waiting==0) {
//do your Job intended to be done after forEach is completed
}
}
与
奇怪的是,异步情况下给出了多少不正确的答案! 可以简单地看出,检查索引并不能提供预期的行为:
// INCORRECT
var list = [4000, 2000];
list.forEach(function(l, index) {
console.log(l + ' started ...');
setTimeout(function() {
console.log(index + ': ' + l);
}, l);
});
输出:
4000 started
2000 started
1: 2000
0: 4000
如果我们检查索引===array.length-1
,则在第一次迭代完成时将调用回调,而第一个元素仍处于挂起状态
要解决这个问题而不使用外部库(如async),我认为最好的办法是节省列表的长度,并在每次迭代后减少if。因为只有一个线程,所以我们确信不可能出现比赛状态
var list = [4000, 2000];
var counter = list.length;
list.forEach(function(l, index) {
console.log(l + ' started ...');
setTimeout(function() {
console.log(index + ': ' + l);
counter -= 1;
if ( counter === 0)
// call your callback here
}, l);
});
我的解决方案:
//对象forEachDone
Object.defineProperty(Array.prototype,“forEachDone”{
可枚举:false,
值:功能(任务,cb){
var计数器=0;
this.forEach(函数(项、索引、数组){
任务(项、索引、数组);
if(array.length===++计数器){
if(cb)cb();
}
});
}
});
//阵列预测
Object.defineProperty(Object.prototype,“forEachDone”{
可枚举:false,
值:功能(任务,cb){
var obj=这个;
var计数器=0;
Object.keys(obj.forEach)(函数(键、索引、数组){
任务(obj[key],key,obj);
if(array.length===++计数器){
if(cb)cb();
}
});
}
});
例如:
var-arr=['a','b','c'];
arr.forEachDone(功能(项目){
控制台日志(项目);
},函数(){
console.log('done');
});
//输出:a b c完成
检查完整迭代计数的setInterval如何。虽然不确定它是否会使作用域过载,但我使用它,而且似乎是唯一的一个
_.forEach(actual_JSON, function (key, value) {
// run any action and push with each iteration
array.push(response.id)
});
setInterval(function(){
if(array.length > 300) {
callback()
}
}, 100);
我的解决方案没有承诺(这确保了每一个行动都在下一个行动开始之前结束):
Array.prototype.forEachAsync=函数(回调,结束){
var self=这个;
功能任务(索引){
var x=自[指数];
如果(索引>=自身长度){
完()
}
否则{
回调(self[index],索引,self,函数(){
任务(索引+1);
});
}
}
任务(0);
};
var i=0;
var myArray=Array.apply(null,数组(10)).map(函数(项){return i++;});
log(JSON.stringify(myArray));
forEachAsync(函数(项、索引、arr、下一步){
setTimeout(函数(){
$(“.toto”).append(“项目索引”+项目+“完成”);
控制台日志(“操作”+项目+“完成”);
next();
}, 300);
},函数(){
$(“.toto”).append(“所有操作均已完成”);
日志(“所有操作都已完成”);
});代码>
我尝试了一种简单的解决方法,与您分享:
let counter = 0;
arr.forEach(async (item, index) => {
await request.query(item, (err, recordset) => {
if (err) console.log(err);
//do Somthings
counter++;
if(counter == tableCmd.length){
sql.close();
callback();
}
});
request
是节点js中mssql库的函数。这可以替换您想要的每个函数或代码。
GoodLuck使用ES2018,您可以使用异步迭代器:
const asyncFunction = a => fetch(a);
const itemDone = a => console.log(a);
async function example() {
const arrayOfFetchPromises = [1, 2, 3].map(asyncFunction);
for await (const item of arrayOfFetchPromises) {
itemDone(item);
}
console.log('All done');
}
但是,请注意,如果forEach中存在异步内容(例如,您正在通过URL数组进行循环并对其执行HTTP GET),则不能保证res.end将在最后调用。为了在循环中执行异步操作后触发回调,可以使用异步实用程序的each方法:为什么不使用if(index==array.length-1)
并删除项处理
@AminJafari,因为异步调用可能无法按照它们被调用的确切顺序解析
var list = [4000, 2000];
var counter = list.length;
list.forEach(function(l, index) {
console.log(l + ' started ...');
setTimeout(function() {
console.log(index + ': ' + l);
counter -= 1;
if ( counter === 0)
// call your callback here
}, l);
});
_.forEach(actual_JSON, function (key, value) {
// run any action and push with each iteration
array.push(response.id)
});
setInterval(function(){
if(array.length > 300) {
callback()
}
}, 100);
let counter = 0;
arr.forEach(async (item, index) => {
await request.query(item, (err, recordset) => {
if (err) console.log(err);
//do Somthings
counter++;
if(counter == tableCmd.length){
sql.close();
callback();
}
});
var i=0;
const waitFor = (ms) =>
{
new Promise((r) =>
{
setTimeout(function () {
console.log('timeout completed: ',ms,' : ',i);
i++;
if(i==data.length){
console.log('Done')
}
}, ms);
})
}
var data=[1000, 200, 500];
data.forEach((num) => {
waitFor(num)
})
const asyncFunction = a => fetch(a);
const itemDone = a => console.log(a);
async function example() {
const arrayOfFetchPromises = [1, 2, 3].map(asyncFunction);
for await (const item of arrayOfFetchPromises) {
itemDone(item);
}
console.log('All done');
}
var counter = 0;
var listArray = [0, 1, 2, 3, 4];
function callBack() {
if (listArray.length === counter) {
console.log('All Done')
}
};
listArray.forEach(function(element){
console.log(element);
counter = counter + 1;
callBack();
});