Callback after all asynchronous forEach callbacks are completed

Array.forEach does not provide this nicety (oh if it would) but there are several ways to accomplish what you want:

Using a simple counter

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

var itemsProcessed = 0;

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

(thanks to @vanuan and others) This approach guarantees that all items are processed before invoking the “done” callback. You need to use a counter that gets updated in the callback. Depending on the value of the index parameter does not provide the same guarantee, because the order of return of the asynchronous operations is not guaranteed.

Using ES6 Promises

(a promise library can be used for older browsers):

  1. Process all requests guaranteeing synchronous execution (e.g. 1 then 2 then 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. Process all async requests without “synchronous” execution (2 may finish faster than 1)

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

Using an async library

There are other asynchronous libraries, async being the most popular, that provide mechanisms to express what you want.

Edit


The body of the question has been edited to remove the previously synchronous example code, so i’ve updated my answer to clarify.
The original example used synchronous like code to model asynchronous behaviour, so the following applied:

array.forEach is synchronous and so is res.write, so you can simply put your callback after your call to foreach:

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

  res.end();

Leave a Comment