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.
Inside an async function, you can use the await keyword before a call to a function that returns a promise. This makes the code wait at that point until the promise is settled, at which point the fulfilled value of the promise is treated as a return value, or the rejected value is thrown.
The await keyword is used in an async function to ensure that all promises returned in the async function are synchronized, ie. they wait for each other. Await eliminates the use of callbacks in .
You haven't been very specific with your code, so I'll make up a scenario. Let's say you have 10 ajax calls and you want to accumulate the results from those 10 ajax calls and then when they have all completed you want to do something. You can do it like this by accumulating the data in an array and keeping track of when the last one has finished:
Manual Counter
var ajaxCallsRemaining = 10; var returnedData = []; for (var i = 0; i < 10; i++) { doAjax(whatever, function(response) { // success handler from the ajax call // save response returnedData.push(response); // see if we're done with the last ajax call --ajaxCallsRemaining; if (ajaxCallsRemaining <= 0) { // all data is here now // look through the returnedData and do whatever processing // you want on it right here } }); }
Note: error handling is important here (not shown because it's specific to how you're making your ajax calls). You will want to think about how you're going to handle the case when one ajax call never completes, either with an error or gets stuck for a long time or times out after a long time.
jQuery Promises
Adding to my answer in 2014. These days, promises are often used to solve this type of problem since jQuery's $.ajax()
already returns a promise and $.when()
will let you know when a group of promises are all resolved and will collect the return results for you:
var promises = []; for (var i = 0; i < 10; i++) { promises.push($.ajax(...)); } $.when.apply($, promises).then(function() { // returned data is in arguments[0][0], arguments[1][0], ... arguments[9][0] // you can process it here }, function() { // error occurred });
ES6 Standard Promises
As specified in kba's answer: if you have an environment with native promises built-in (modern browser or node.js or using babeljs transpile or using a promise polyfill), then you can use ES6-specified promises. See this table for browser support. Promises are supported in pretty much all current browsers, except IE.
If doAjax()
returns a promise, then you can do this:
var promises = []; for (var i = 0; i < 10; i++) { promises.push(doAjax(...)); } Promise.all(promises).then(function() { // returned data is in arguments[0], arguments[1], ... arguments[n] // you can process it here }, function(err) { // error occurred });
If you need to make a non-promise async operation into one that returns a promise, you can "promisify" it like this:
function doAjax(...) { return new Promise(function(resolve, reject) { someAsyncOperation(..., function(err, result) { if (err) return reject(err); resolve(result); }); }); }
And, then use the pattern above:
var promises = []; for (var i = 0; i < 10; i++) { promises.push(doAjax(...)); } Promise.all(promises).then(function() { // returned data is in arguments[0], arguments[1], ... arguments[n] // you can process it here }, function(err) { // error occurred });
Bluebird Promises
If you use a more feature rich library such as the Bluebird promise library, then it has some additional functions built in to make this easier:
var doAjax = Promise.promisify(someAsync); var someData = [...] Promise.map(someData, doAjax).then(function(results) { // all ajax results here }, function(err) { // some error here });
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); });
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With