[javascript] How can I wait for set of asynchronous callback functions?

I have code that looks something like this in javascript:

forloop {
    //async call, returns an array to its callback
}

After ALL of those async calls are done, I want to calculate the min over all of the arrays.

How can I wait for all of them?

My only idea right now is to have an array of booleans called done, and set done[i] to true in the ith callback function, then say while(not all are done) {}

edit: I suppose one possible, but ugly solution, would be to edit the done array in each callback, then call a method if all other done are set from each callback, thus the last callback to complete will call the continuing method.

Thanks in advance.

This question is related to javascript asynchronous

The answer is


You can emulate it like this:

  countDownLatch = {
     count: 0,
     check: function() {
         this.count--;
         if (this.count == 0) this.calculate();
     },
     calculate: function() {...}
  };

then each async call does this:

countDownLatch.count++;

while in each asynch call back at the end of the method you add this line:

countDownLatch.check();

In other words, you emulate a count-down-latch functionality.


Use an control flow library like after

after.map(array, function (value, done) {
    // do something async
    setTimeout(function () {
        // do something with the value
        done(null, value * 2)
    }, 10)
}, function (err, mappedArray) {
    // all done, continue here
    console.log(mappedArray)
})

This is the most neat way in my opinion.

Promise.all

FetchAPI

(for some reason Array.map doesn't work inside .then functions for me. But you can use a .forEach and [].concat() or something similar)

Promise.all([
  fetch('/user/4'),
  fetch('/user/5'),
  fetch('/user/6'),
  fetch('/user/7'),
  fetch('/user/8')
]).then(responses => {
  return responses.map(response => {response.json()})
}).then((values) => {
  console.log(values);
})

Checking in from 2015: We now have native promises in most recent browser (Edge 12, Firefox 40, Chrome 43, Safari 8, Opera 32 and Android browser 4.4.4 and iOS Safari 8.4, but not Internet Explorer, Opera Mini and older versions of Android).

If we want to perform 10 async actions and get notified when they've all finished, we can use the native Promise.all, without any external libraries:

function asyncAction(i) {
    return new Promise(function(resolve, reject) {
        var result = calculateResult();
        if (result.hasError()) {
            return reject(result.error);
        }
        return resolve(result);
    });
}

var promises = [];
for (var i=0; i < 10; i++) {
    promises.push(asyncAction(i));
}

Promise.all(promises).then(function AcceptHandler(results) {
    handleResults(results),
}, function ErrorHandler(error) {
    handleError(error);
});

You can use jQuery's Deferred object along with the when method.

deferredArray = [];
forloop {
    deferred = new $.Deferred();
    ajaxCall(function() {
      deferred.resolve();
    }
    deferredArray.push(deferred);
}

$.when(deferredArray, function() {
  //this code is called after all the ajax calls are done
});