sbaden sbaden - 2 months ago 8
Javascript Question

Hoisting or Callback issue? Finish for(loop) before writeLog() but log writes before done

I'm trying to loop thru an array of teams to get player data and pass the data to an object. My ajax call gets the files. After looping thru all teams I then want to write a log with the data collected. The problem is that writeLog() is called immediately - I think - not waiting for the loop to finish. Is this a hoisting problem? A callback issue? How can I refactor my code to writeLog() after for loop is finished?

(function(){

$('#generate-report').on('click', function(){

var logObj = {
playerCount: 0,
firstNameArray: [],
lastNameArray: [],
firstNameCharCount: 0,
lastNameCharCount: 0,
resultFirst: 0,
resultLast: 0,
freqReportFirst: "First name\n",
freqReportLast: "Last name\n",
freqObjFirst: {},
freqObjLast: {},
}

var url = "http://feeds.nfl.com/feeds-rs/roster/";

var teams = new Array("3800", "0200", "0325", "0610", "0750", "0810", "0920", "1050",
"1200", "1400", "1540", "1800", "2120", "2200", "2250", "2310",
"2700", "3000", "3200", "3300", "3410", "3430", "2520", "3700",
"3900", "4400", "4600", "4500", "2510", "4900", "2100", "5110"
);
//var teams = new Array("3800"); // For testing

for(var i=0; i<teams.length; i++){
console.log(teams[i]);
$.ajax({
url: url + teams[i] + ".json",
type: 'GET',
success: function(response){
processPlayerNames(response, logObj);
},
error: function(response){
console.log(response);
}
});
};

writeLog(logObj);

});


})();

Answer

$.ajax() returns results asynchronously. You can push $.ajax() call to an array, then use Promise.all(), .map() on array of promise objects, or use $.when(), Function.prototype.apply(), .map() to perform all asynchronous tasks before calling writeLog() at .then() chained to variable representing jQuery promise object returned from $.when() call.

var requests = $.when.apply(null, teams.map(function(team) {
  return $.ajax({
            url: url + team + ".json",
            type: 'GET',
            success: function(response){
                processPlayerNames(response, logObj);
            }
        });
}));

requests.then(function() {
  writeLog(logObj)
}, function(response){
  console.log(response);
});