How to properly loop through HTTP requests using XMLHttpRequest()?

xhr request in loop
xhr in a loop
multiple xmlhttprequest in loop
http request in loop javascript
xmlhttprequest not returning data
xmlhttprequest response json
fetch api
how to parse xmlhttprequest response

I am currently learning vanilla JS before jumping into any major frameworks so I can get the grip with HTTP request mechanics. I am sure there are a ton of better JS libraries for HTTP requests but I want to figure out how to solve my problem using classic XMLHttpRequest(), therefore please do not suggest any solutions that do not include XMLHttpRequest().

I am trying to loop through an array I have and make HTTP GET requests to an API with the information in the array and then populate my HTML with the response data. The code is quite simple:

Function that takes in my array of numbers:

function loadUniqueProjs(uniqueArray)
{

    var reqObject = [];

    for (var i in unique_array) 
    {
         outsideLoopRequest(unique_array[i], reqObject, i);
    }


}

I loop through the array and execute a function that is supposed to execute my GET request:

function outsideLoopRequest(arrayValue,reqObject, i){

    // Create XHR Object
    reqObject[i] = new XMLHttpRequest();
    reqObject[i].open('GET', 'http://localhost:3000/resource/Projects/' + arrayValue, true)

    reqObject[i].onload = function() {
        if (this.status == 200) {
            var client = JSON.parse(this.responseText);
            var output = '';

            for (var j in client){

                output +=   '<div class="card">'+
                                    '<h5 class="card-header" role="tab" id="heading'+ j + '">'+
                                        '<a data-toggle="collapse" data-parent="#accordion" style="color:black"' + 
                                            'href="#collapse' + j + '"aria-expanded="false" aria-controls="collapse' + j + '"class="d-block collapsed">' +
                                            '<i class="fa fa-angle-double-down pull-right"></i>#' +
                                            client[j].projectTitle + ' | ' + 'PM: ' + client[j].projectManager + ' | ' +
                                            'PO: ' + client[j].projectOwner + ' | ' + 'Estimated Deadline: ' + client[j].predictedCompletion +
                                            ' | ' + 'Status: ' + client[j].status +
                                            ' | ' + 'Requestor: ' + client[j].requestor +
                                        '</a>'+
                                    '</h5>'+
                            '</div>';
            }
    }

    document.getElementById("spinner").hidden = true;
    // output the data into the HTML page
    document.getElementById('accordion').innerHTML = output;

    console.log(this.status + ' Data retrieved successfully!');

}
    reqObject[i].send();
}

After hours of step by step debugging I learned that the HTTP requests are asynchronous and when utilising a loop to execute the requests one by one they won't behave like you want them to. The requests do not get executed one by one adding the HTML I require, instead the loop opens all requests first and then executes as they come, and when stepping through code in the web debugger the code jumps around all over the place it gets extremely confusing (sorry for rant).

I would like it to behave step by step. I did research on SO and someone suggested that these are scoping issues and that the requests should be made in a separate function, which is why I have structured my code with the loop in one function and the request execution in another but its still missbehaving as described previously. Is there anyone that could share their expertise please?

  1. The only way to do something after XMLHttpRequest has completed is to pass that "something" as a callback. For a chain of request, you'll have to do it recursively, so the first one will have to receive an ordered list of all the requests to execute after plus the finishing callback to do after the final one is completed. The code will probably get ugly, I'm not going to try.

  2. You can still send all your requests right away and render the data in the correct order as they come. Start with creating the basic skeleton structure of the output data

var outputStructure = '';

for (var i in unique_array) {
   var cardId = 'card-' + id;
   outputStructure += `<div class="card" id="card-${i}">`;
   outsideLoopRequest(unique_array[i], reqObject, i);
}

document.getElementById('accordion').innerHTML = outputStructure;

and on completion, put the data in the card with the right id.

    reqObject[i].onload = function() {
// create the output structure, then
       document.getElementById(`card-${i}`).innerHTML = output;
  1. Problems as such are a part of what is colloquially called "callback hell". It's simply so much easier to organize more complicated async operations (where some things can be done in parallel, others must wait until the previous one has completed) with promises. Do stuff after all requests have been completed? One line: Promise.all(requests).then(//....

Use fetch.

Having trouble looping through xmlhttprequest GET with my array , Having trouble looping through xmlhttprequest GET with my array, if this is how to correctly pass arrays through an httpRequest either. I'm not sure why but I'm going to try to put the for loop over my Make Request function new XMLHttpRequest(); if (!httpRequest) { alert("can not create http instance! The XMLHttpRequest object contains several class properties that you’ll need to know about to handle the HTTP response from the web server. After you use the send () method to send a connection request to a web server, the HTTP connection process works through five connection states, as tracked by the readyState property:

Here is an implementation sample of you're trying to. Each request will be executed one by one synchronously.

var index = 0;
var uniqueArray = ['a', 'b', 'c'];
var output = '';

function http(arrayValue) {
  var url = 'http://localhost:3000/resource/Projects/' + arrayValue;

  var xhr = new XMLHttpRequest();
  xhr.onreadystatechange = function() {
    if (xhr.readyState == XMLHttpRequest.DONE) {
      onHttpDone(xhr);
    }
  };

  xhr.open('GET', url, true);
  xhr.send();
}

function onHttpDone(xhr) {
  if (xhr.status != 200) {
    console.log('HTTP ERROR: ' + xhr.status);
    return;
  }

  var client = JSON.parse(xhr.responseText);

  output += '<div class="card">' + client.someProperty + '</div>';
  document.getElementById('accordion').innerHTML = output;

  if (index < uniqueArray.length) {
    http(uniqueArray[index++]);
  }
}

http(uniqueArray[index++]);

Be the Master of the Event Loop in JavaScript (Part 3), const oReq = new XMLHttpReqeust();. Now oReq has the XMLHttpRequest object. To make an HTTP request, you should open the request first. XMLHttpRequest is a built-in browser object that allows to make HTTP requests in JavaScript. Despite of having the word “XML” in its name, it can operate on any data, not only in XML format. We can upload/download files, track progress and much more.

Modern JS provides a number of new ways to work with async operations. Instead of calling the API and trying to return data with each iteration we can work with promises.

1) Make an array of promises to pass to Promise.all

This iterates over your array with map to produce a new array of promises produced with fetch (similar to XMLHTTPRequest but promise-based) and an endpoint based on the array element in that iteration. (I've used a template literal to create the endpoint string rather than string concatenation).

const promises = unique_array.map(el => {
  const endpoint = `http://localhost:3000/resource/Projects/${el}`;
  return fetch(endpoint);
});

2) Now we have an array of promises we simply need to give it to Promise.all which also returns a promise with the result of calling all those API endpoints. Using that data you can then loop over it to create your HTML.

Promise.all(promises).then(data => {
  // loop over the data to create the HTML
});

How about an example?

// We use a dummy fetch function to mimic a call to an
// API. Data is returned after two seconds. It is an object
// containing a number, and the square of that number
function dummyFetch(n) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({ number: n, square: n * n });
    }, 2000);
  });
}

const arr = [1, 2, 3, 4];

// We produce the array of promises
const promises = arr.map(el => dummyFetch(el));

// When the promises have been resolved/rejected...
Promise.all(promises).then(data => {

  // ...we can iterate over the data and produce an
  // array of html
  const html = data.map(({ number, square }) => {
    return `
      <div>
        <span class="number">${number}</span>
        <span class="square">${square}</span>
      </div>
    `
  }).join('');

  // ...which we can then add to the page 
  document.body.insertAdjacentHTML('beforeend', html);
});
.number { color: red; }
.square { color: blue; }

Fetch, The promise rejects if the fetch was unable to make HTTP-request, e.g. It's not exactly a Map, but it has similar methods to get individual headers by name or iterate over them: These headers ensure proper and safe HTTP, so they are controlled Does fetch use XMLHttpRequest under the hood? The XMLHttpRequest Object. The XMLHttpRequest object can be used to request data from a web server. The XMLHttpRequest object is a developers dream, because you can: Update a web page without reloading the page; Request data from a server - after the page has loaded ; Receive data from a server - after the page has loaded

Beginners Guide To Fetching Data With (AJAX, Fetch API & Async , Request is being sent by making an AJAX call, Data in JSON format is responseText)); } } //call send xhr.send(); //Common Types of HTTP� The signature of the utility function loadFile declares (i) a target URL to read (via an HTTP GET request), (ii) a function to execute on successful completion of the XHR operation, and (iii) an arbitrary list of additional arguments that are passed through the XHR object (via the arguments property) to the success callback function.

Using Cypress, Can I store an attribute's value in a constant or a variable for later use? How do I wait for multiple XHR requests to the same url? Is there a way to give a proper SSL certificate to your proxy so the page doesn't How do I use special characters with cy.get()?; Can I use Cypress to test charts and graphs? A common use of JSON is to read data from a web server, and display the data in a web page. This chapter will teach you, in 4 easy steps, how to read JSON data, using XMLHttp.

Beginning JSON, getElementsByTagName("body")[0]; 6 var xhr = (window. When the button is clicked, the function loadImages (line 4) initiates the HTTP request. we must first determine what object must be instantiated, to make the proper request. From there, using a for loop, we iterate over each and every index possessed by our� var body = XMLHttpRequest.response; Value. An appropriate object based on the value of responseType. You may attempt to request the data be provided in a specific format by setting the value of responseType after calling open() to initialize the request but before calling send() to send the request to the server.

Comments
  • Thanks for the explanation. I think @Andy & @Takashi Harano showed your suggestion 1 & 3 in code, which I will study later. I implemented your 2, the only issue was the lack of </div> closing tag in outputStructure+= thus making cards within cards and output dispalying only 1 card.