1

I need to send multiple get requests in a loop, and the callback that processes the response needs the index of the loop in order to combine the response data with the data I already had about each object.

From this, I know how to create a single request and use a callback to pass extra parameters. I am also able to send multiple requests and use XMLHttpRequest.onreadystatechange to set a function for the result.

I tried combining the two solutions, but because it's a loop, the variables change after each iteration and all the responses end up being called with the parameters of the last iteration of the loop. I thought using var indexOfProject = i; inside the loop would solve the problem, but it didn't. Here's my code:

var count = 0;
var queryProjects = 2;
var totalNeeded = queryProjects;

var apicallback = function(project, index) {
    if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {  
        console.log("processing response, index, project : " + index);
        console.log(project);
        var objResponse = JSON.parse(xmlHttp.responseText);
        _projectsData.projects[index]['lastUpdateTime'] = objResponse['updated_at'];
        count++;
        if (count==totalNeeded){
            console.log("got all responses!");
            //TODO: 
        }
    }
};

for (var i = 0; i < queryProjects; i++) {
    var indexOfProject = i;
    if (repos[i] != null) {
        var theUrl = "https://api.github.com/repos/" + repos[i][0];
        var xmlHttp = new XMLHttpRequest();
        xmlHttp.onreadystatechange = function() { 
            apicallback(_projectsData.projects[indexOfProject], indexOfProject); 
        }
        console.log("sent request!");
        xmlHttp.open("GET", theUrl, true); // true for asynchronous 
        xmlHttp.send(null);
    }
    else {
        totalNeeded--;
    }
}

I also tried this,

xmlHttp.onreadystatechange = apicallback(_projectsData.projects[indexOfProject], indexOfProject); 

but it was even worse because the callback is only called once, when readystate==1.

  • https://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example – epascarello Feb 01 '19 at 12:58
  • Easiest thing, break it out into a function and call it with the loop varaible. – epascarello Feb 01 '19 at 12:59
  • @epascarello The parameters are working now, but the callback seems to run twice for some of my entries. And I mean twice with `xmlHttp.readyState == 4` being true, which messes up with my data. Of course I can handle duplicates, but it also looks like for some of the entries the callback doesn't run at all. This problem didn't occur before. Any ideas? – Savvas Parastatidis Feb 01 '19 at 15:26
  • Did you add console.log statements to see what the xmlHttp.status is? – epascarello Feb 01 '19 at 15:30
  • Yes. the readystate usually goes through all values from 1 to 4, and status starts with 0 and becomes 200 after readystate is 2. It also looks like the entry that doesn't trigger is always the same, but it runs fine on its own. – Savvas Parastatidis Feb 01 '19 at 15:37
  • See anything weird in network tab? – epascarello Feb 01 '19 at 15:39
  • Network tab looks like the requests are executed properly. But still console.log messages show that the response handler is executed multiple times for some requests and never for others. – Savvas Parastatidis Feb 01 '19 at 17:51
  • @epascarello I found it. I was using `xmlHttp.readyState` to read the readystate and status, but `xmlHttp` was another variable that was changed by the loop, so even though the callback was working properly, I kept using the same xmlHttp variable to refer to the requests. Changing to `this.readystate` solved the problem. Thanks for the tips! – Savvas Parastatidis Feb 01 '19 at 18:16

0 Answers0