Callback after all async forEach callbacks complete


Andreasson:

as the title suggests. What should I do?

I want to call whenAllDone()after the forEach loop goes through each element and does some async processing .

[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();
  }
);

Is it possible to make it work like this? When the second argument to forEach is a callback function that runs once all iterations have passed?

Expected output:

3 done
1 done
2 done
All done!
Nick Tomlin:

Array.forEachCan't provide this effect (if you can), but there are several ways to achieve what you want:

use 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 et al), this approach ensures that all items are processed before the "done" callback is called. You need to use the counter updated in the callback. Relying on the value of the index parameter does not provide the same guarantee, because the return order of asynchronous operations is not guaranteed.

Use ES6 promises

(the promise library is available for older browsers):

  1. Process all requests guaranteed to be executed synchronously (e.g. 1 to 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 asynchronous 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'));
    

Use async library

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

edit

The body of the question was edited to remove the previously synced sample code, so I've updated the answer to clarify. The original example uses synchronous-like code to model asynchronous behavior, so the following applies:

array.forEachis synchronous, too res.write, so you just put the callback after calling the foreach:

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

  res.end();

Related


Callback after all async forEach callbacks complete

Andreasson: as the title suggests. What should I do? I want to call whenAllDone()after the forEach loop goes through each element and does some async processing . [1, 2, 3].forEach( function(item, index, array, done) { asyncFunction(item, function itemD

Callback after all async forEach callbacks complete

Andreasson: as the title suggests. What should I do? I want to call whenAllDone()after the forEach loop goes through each element and does some async processing . [1, 2, 3].forEach( function(item, index, array, done) { asyncFunction(item, function itemD

forEach, async and callbacks

Zonelsk Sorry if this question has been answered before but I can't find it. I have an array of objects, for each object I want to make an async call (ajax call) and when all the async calls are done I want to call another function. E.g. var list = [Object

forEach, async and callbacks

Zonelsk Sorry if this question has been answered before but I can't find it. I have an array of objects, for each object I want to make an async call (ajax call) and when all the async calls are done I want to call another function. E.g. var list = [Object

Async functions and callbacks in forEach loops

Mrdakovac Inside this function: function Example(array, callback){ var toReturn = []; // variable 'array' has 2 elements in this case array.forEach(function(el){ MongooseModel.AsyncFunction(el, function(err, doc){ if(err || !do

Async functions and callbacks in forEach loops

Mrdakovac Inside this function: function Example(array, callback){ var toReturn = []; // variable 'array' has 2 elements in this case array.forEach(function(el){ MongooseModel.AsyncFunction(el, function(err, doc){ if(err || !do

Async functions and callbacks in forEach loops

Mrdakovac Inside this function: function Example(array, callback){ var toReturn = []; // variable 'array' has 2 elements in this case array.forEach(function(el){ MongooseModel.AsyncFunction(el, function(err, doc){ if(err || !do

Async functions and callbacks in forEach loops

Mrdakovac Inside this function: function Example(array, callback){ var toReturn = []; // variable 'array' has 2 elements in this case array.forEach(function(el){ MongooseModel.AsyncFunction(el, function(err, doc){ if(err || !do

Async functions and callbacks in forEach loops

Mrdakovac Inside this function: function Example(array, callback){ var toReturn = []; // variable 'array' has 2 elements in this case array.forEach(function(el){ MongooseModel.AsyncFunction(el, function(err, doc){ if(err || !do

Async functions and callbacks in forEach loops

Mrdakovac Inside this function: function Example(array, callback){ var toReturn = []; // variable 'array' has 2 elements in this case array.forEach(function(el){ MongooseModel.AsyncFunction(el, function(err, doc){ if(err || !do

Javascript - Callback after all nested forEach loops are done

Reza Karami I'm sure this is a fairly simple task, but at the moment I can't figure it out. I have a set of nested forEach loops and need a callback when all loops have finished running. I am willing to use async.js This is what I'm using: const scanFiles = fu

Javascript - Callback after all nested forEach loops are done

Reza Karami I'm sure this is a fairly simple task, but at the moment I can't figure it out. I have a set of nested forEach loops and need a callback when all loops have finished running. I am willing to use async.js This is what I'm using: const scanFiles = fu

Javascript - Callback after all nested forEach loops are done

Reza Karami I'm sure this is a fairly simple task, but at the moment I can't figure it out. I have a set of nested forEach loops and need a callback when all loops have finished running. I am willing to use async.js This is what I'm using: const scanFiles = fu

Javascript - Callback after all nested forEach loops are done

Reza Karami I'm sure this is a fairly simple task, but at the moment I can't figure it out. I have a set of nested forEach loops and need a callback when all loops have finished running. I am willing to use async.js This is what I'm using: const scanFiles = fu

Javascript - Callback after all nested forEach loops are done

Reza Karami I'm sure this is a fairly simple task, but at the moment I can't figure it out. I have a set of nested forEach loops and need a callback when all loops have finished running. I am willing to use async.js This is what I'm using: const scanFiles = fu

Wait for all callbacks to complete before returning the object

garbage robber I have a function that needs to scrape a website and return a list of addresses. In the callback from the grab, for each address returned, I need to do another grab, then process the data, and then I want to return the entire processed collectio

Wait for all callbacks to complete before returning the object

garbage robber I have a function that needs to scrape a website and return a list of addresses. In the callback from the grab, for each address returned, I need to do another grab, then process the data, and then I want to return the entire processed collectio

Run callbacks after multiple functions complete

juicy I have multiple time consuming functions and I want to run a function after they all finish, eg: data.x = thisTakes2Seconds(); data.y = thisTakes5Seconds(); http.post(data); I'm familiar with the concept of callbacks in Javascript, but if I have multipl

Callback after pdf export is complete

Stephen Is there a way to specify a callback function for pdfMake's createPdffunctions ? My vfs_fonts.jsfiles are huge , that's why my export is slow. Loren There is a callback function getDataUrl: this.getDataUrl(function(result) { win.location.href = res

Callback after dialog transition is complete

Tony Ronaldo Vuetify has some nice built-in transitions. But how do I call the method when the default dialog scale animation is done? https://codepen.io/anon/pen/qKNNLw <v-dialog v-model="dialog" persistent max-width="200"> <v-btn slot="activator">Open</v-b

Callback after pdf export is complete

Stephen Is there a way to specify a callback function for the pdfMake createPdffunction ? My vfs_fonts.jsfiles are huge , that's why my export is slow. Lauren There is a callback function getDataUrl: this.getDataUrl(function(result) { win.location.href = r

Callback after pdf export is complete

Stephen Is there a way to specify a callback function for the pdfMake createPdffunction ? My vfs_fonts.jsfiles are huge , that's why my export is slow. Lauren There is a callback function getDataUrl: this.getDataUrl(function(result) { win.location.href = r

Callback after dialog transition is complete

Tony Ronaldo Vuetify has some nice built-in transitions. But how do I call the method when the default dialog scale animation is done? https://codepen.io/anon/pen/qKNNLw <v-dialog v-model="dialog" persistent max-width="200"> <v-btn slot="activator">Open</v-b

Callback after pdf export is complete

Stephen Is there a way to specify a callback function for pdfMake's createPdffunctions ? My vfs_fonts.jsfiles are huge , that's why my export is slow. Loren There is a callback function getDataUrl: this.getDataUrl(function(result) { win.location.href = res

Callback after pdf export is complete

Stephen Is there a way to specify a callback function for pdfMake's createPdffunctions ? My vfs_fonts.jsfiles are huge , that's why my export is slow. Loren There is a callback function getDataUrl: this.getDataUrl(function(result) { win.location.href = res