2

I'm trying to display the progress of a file being loaded through an XMLHttpRequest using bootstrap's progress bar. Unfortunately the progress bar only updates when the file has loaded (ie it stays at 0% while the file is loading, then jumps to 100% when it's done). I realise this is because the UI and javascript are run on the same thread but I don't know how to get around it. I've tried numerous alternatives such as intervals and workers.

Here is my code:

Loading the file and running the progress eventListener:

        var xhr = createXHR();

        xhr.open('GET', path, true);

        xhr.addEventListener("progress", updateProgress);

        xhr.onreadystatechange = function(evt) {
        ...
        }

updateProgress funtion:

var percentComplete = 0;
function updateProgress (oEvent) {
    if (oEvent.lengthComputable) {
        percentComplete = oEvent.loaded / oEvent.total;
        console.log(percentComplete);
    } else {
        // 
    }
}

This code is run once the file starts loading, attempts to use setInterval as it is asyncronous:

var progress = setInterval(function(){
    //update the progressbar
    $('#progress-bar').css('width', Math.round10(percentComplete*100, 2)+'%');

    if(percentComplete==1){
        $('#progress-modal').modal('toggle'); //Close the progress bar
        clearInterval(progress); //clear the setInterval
    }

}, 50)

I thought that setInterval being asyncronous would solve this, but it doesn't. The console.log method works well - if I could update the progressbar similarly that would be perfect. Could someone point out what I'm doing wrong?

J VR
  • 61
  • 7

3 Answers3

0

No need to wrap your progress bar updates in setInterval. Move that code directly into your updateProgress function.

var percentComplete = 0;
function updateProgress (oEvent) {
  if (oEvent.lengthComputable) {
    percentComplete = oEvent.loaded / oEvent.total;
    console.log(percentComplete);

    $('#progress-bar').css('width', Math.round10(percentComplete*100, 2)+'%');

    if(percentComplete==1){
      $('#progress-modal').modal('toggle'); //Close the progress bar
    }
  } else {
    // 
  }
}
  • Sorry I must not have been clear with what the problem is. The progressbar would not update until the load was 100% complete, rather than update as it loaded (ie 5%...12%...23%...etc). AFAIK this is because the UI is not updated until the javascript code is complete as they run on the same thread. That's what the setInterval code was attempting to fix, because I think it's supposed to be run on another thread. I tried your code, still the same problem. – J VR Mar 24 '18 at 03:33
  • Glad to see you worked it out and that it was just a math error. https://stackoverflow.com/a/7575649/7650673 can probably help shed some more light on how JavaScript's single-threaded nature affects (or doesn't affect) the way asynchronous code runs. – Marc Schroth Mar 26 '18 at 07:49
0

I think your code lacks a variable that you should update as the bar progresses. you can check this code here http://js.do/code/205468 .Its written in javascript, hope it helps.

  • The $('#progress-bar').css('width'...) is the equivalent variable that you're referring to. It functions correctly as the width is altered when the file is downloaded (i.e it shoots up to 100%). The issue is that this updating of the width doesn't occur while the file is downloading, but only at the end (which I think is related to what I mentioned about threads) – J VR Mar 24 '18 at 05:03
0

Got it working. Unfortunately the issue seemed to be in the calculation for the width (the Math.round10() function). The code is now:

var percentComplete = 0;
function updateProgress (oEvent) {
    if (oEvent.lengthComputable) {
        percentComplete = 100* oEvent.loaded / oEvent.total;
    } else {
        //
    }
}

.

var i = setInterval(function(){
    $('#progress-bar').css('width', percentComplete+"%");

    if(percentComplete>=100) {
        $('#progress-modal').modal('toggle');
        clearInterval(i);
    }
}, 50);

Sorry - I was expecting this question would allow for a good bit of discussion around progress bars and threads, not just a silly bit of weird code. For anybody from the future - setInterval seems to be the way to go to update progress bars on the fly.

J VR
  • 61
  • 7