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

问题描述

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 和其他人)这种方法保证在调用“完成”回调之前处理所有项目。您需要使用在回调中更新的计数器。取决于索引参数的值不提供相同的保证,因为异步操作的返回顺序是不保证的。

使用 ES6 承诺

(promise 库可用于旧版浏览器):

  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’));

使用异步库

还有其他异步库,其中async是最流行的,它们提供了表达你想要的东西的机制。

编辑


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

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

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

  res.end();

解决方法

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

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

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