I have a loop that makes calls to an API and compiles the results into an array. How do I wait until all of the calls are finished until resuming execution? I see a bunch of answers for how to wait until one call is done, but I don't understand how to check for all of them. If I make a while loop that waits until 'obj' is the correct length, the page just stalls until the calls are done, which is not what I want. Help please?
function getData(id) {
var thisI = i;
var url = "www.whatever.com?id=" + id;
$.getJSON(url, function(data) {
obj[thisI]=data;
});
}
obj = [];
for (i=0; i < ids.length; i++) {
getData(ids[i]);
}
console.log(obj) //this works! I see all of the elements
document.getElementById("txt").innerHTML=obj[0]['field']; //TypeError: obj[0] is undefined
This is easy if you use jQuery's deferreds. There is a method, $.when
, that waits for multiple promises to complete then runs a callback. That's what you should use here.
Don't use a global obj
variable, you can just use the returns from the AJAX calls.
function getData(id) {
var thisI = i;
var url = "www.whatever.com?id=" + id;
return $.getJSON(url); // this returns a "promise"
}
So, instead of populating obj
, we just return the promise. Then in your loop, you collect all of them.
var AJAX = [];
for (i=0; i < ids.length; i++) {
AJAX.push(getData(ids[i]));
}
Then we need to hook up the callback when all of them are done:
$.when.apply($, AJAX).done(function(){
// This callback will be called with multiple arguments,
// one for each AJAX call
// Each argument is an array with the following structure: [data, statusText, jqXHR]
// Let's map the arguments into an object, for ease of use
var obj = [];
for(var i = 0, len = arguments.length; i < len; i++){
obj.push(arguments[i][0]);
}
document.getElementById("txt").innerHTML = obj[0]['field'];
});
getData
will return a promise which is a read-only version of a deferred. You can then execute code based on the resolution of these promises using $.when