完成所有异步 forEach 回调后的回调

2022-08-30 00:10:42

正如标题所示。我该怎么做?

我想在 forEach 循环遍历每个元素并完成一些异步处理之后调用。whenAllDone()

[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!

答案 1

Array.forEach不提供这种好处(哦,如果它会的话),但是有几种方法可以完成你想要的事情:

使用简单的计数器

function callback () { console.log('all done'); }

var itemsProcessed = 0;

[1, 2, 3].forEach((item, index, array) => {
  asyncFunction(item, () => {
    itemsProcessed++;
    if(itemsProcessed === array.length) {
      callback();
    }
  });
});

(感谢@vanuan和其他人)此方法保证在调用“done”回调之前处理所有项目。您需要使用在回调中更新的计数器。根据 index 参数的值,不会提供相同的保证,因为不保证异步操作的返回顺序。

使用 ES6 承诺

(承诺库可用于较旧的浏览器):

  1. 处理所有保证同步执行的请求(例如,1 然后 2 然后 3)

    function asyncFunction (item, cb) {
      setTimeout(() => {
        console.log('done with', item);
        cb();
      }, 100);
    }
    
    let requests = [1, 2, 3].reduce((promiseChain, item) => {
        return promiseChain.then(() => new Promise((resolve) => {
          asyncFunction(item, resolve);
        }));
    }, Promise.resolve());
    
    requests.then(() => console.log('done'))
    
  2. 在不执行“同步”的情况下处理所有异步请求(2 可能比 1 更快地完成)

    let requests = [1,2,3].map((item) => {
        return new Promise((resolve) => {
          asyncFunction(item, resolve);
        });
    })
    
    Promise.all(requests).then(() => console.log('done'));
    

使用异步库

还有其他异步库,异步是最流行的,它们提供了表达所需内容的机制。

编辑

问题的主体已经过编辑,以删除先前同步的示例代码,因此我更新了我的答案以进行澄清。原始示例使用类似同步的代码来模拟异步行为,因此应用了以下内容:

array.forEach同步的,所以你可以简单地把你的回调放在你的调用之后 foreach:res.write

  posts.foreach(function(v, i) {
    res.write(v + ". index " + i);
  });

  res.end();

答案 2

如果您遇到异步函数,并且想要确保在执行代码之前完成其任务,我们始终可以使用回调功能。

例如:

var ctr = 0;
posts.forEach(function(element, index, array){
    asynchronous(function(data){
         ctr++; 
         if (ctr === array.length) {
             functionAfterForEach();
         }
    })
});

注意:是前几个任务完成后要执行的函数。 是在 foreach 内部执行的异步函数。functionAfterForEachasynchronous