Aparistar Aparistar - 5 months ago 102
jQuery Question

Progress bar for multiple ajax requests with stages of completion. Is it possible?

I have a simple form which when submitted validates via an ajax request. If the form checks out ok, then another ajax request is made to process the data originally submitted.

I want to build a progress bar for this. Ive found that adding this code to each ajax request returns the progress for each call separately. That makes the progress bar load to 100%, twice, quickly.

Is it possible for example for two ajax request to each fill 50% of the progress bar?... So ajax request 1 will fill up to 50% and the second will fill from 51% to 100%? Or is that crazy?

Or if three ajax calls each being responsible for 33.33% of the total percentage?

I guess we are more looking at stages of completion as well as progress.

Any ideas how this could be achieved without too much faking it?

var xhr = new window.XMLHttpRequest();
//Upload progress
xhr.upload.addEventListener("progress", function (evt) {
if (evt.lengthComputable) {
var percentComplete = evt.loaded / evt.total;
//Do something with upload progress
console.log('percent uploaded: ' + (percentComplete * 100));
}
}, false);
//Download progress
xhr.addEventListener("progress", function (evt) {
if (evt.lengthComputable) {
var percentComplete = evt.loaded / evt.total;
//Do something with download progress
console.log('percent downloaded: ' + (percentComplete * 100));
}
}, false);
return xhr;

Answer

Yes, it is possible. You can create an array containing each ajax call. Set <progress> element max attribute to 100/array.length. Divide evt.loaded / evt.total of individual progress event by array .length to set value of <progress> element. You could also use Promise.all(), .then() to process array of functions returning a Promise from ajax call and update <progress> element.


html

<label></label>
<progress value="0" min="0" max="100"></progress>

javascript

var progress = document.querySelector("progress");
var url = "/echo/html/";

function request(url) {
var len = arr.length;
return new Promise(function(resolve, reject) {
  var xhr = new XMLHttpRequest();
  xhr.upload.addEventListener("progress", function(evt) {
    if (evt.lengthComputable) {   
      var percentComplete = ((evt.loaded / evt.total) * (progress.max / len)) 
                            / len -1;
      console.log(progress.value, percentComplete);
      if (evt.total === evt.loaded) {
        requests += 1;
      }
      if (progress.value == progress.max && requests === len) {
        progress.previousElementSibling.innerHTML = "upload complete";
        // you could call `resolve()` here if only interested in
        // `upload` portion of request
        alert("upload complete");
      }
      progress.value += percentComplete;
    }
  }, false);
  xhr.onload = function() {
     resolve(this.responseText)
  };
  xhr.onerror = reject;
  xhr.open("POST", url, true)
  xhr.send("html=" + Array(100000).fill(1).join(""));
  })
}

var arr = [], requests = 0;
arr.push(request, request, request);
Promise.all(arr.map(function(req) {
  return req(url)
}))
.then(function(data) {
  console.log(data);    
})
.catch(function(err) {
  console.log(err)
})

jsfiddle https://jsfiddle.net/v2msL7hj/1/

Comments