2

I'm creating a progam, where JavaScript is processing a huge amount of data, so I want to show the progress on a progressbar.

The problem comes here: While the for loop is running, the progressbar does not update, and then it will be fullfilled immediately.

document.getElementById("start").addEventListener("click",function(){
    max=1000000
    document.getElementById("pb").max=max
    for(i=0;i<max;i++){
        document.getElementById("pb").value=i+1
    }
    console.log("Finished")
})
<progress id="pb" value="0" max="0"></progress>
<input type="button" id="start" value="Start"/>

How can I solve that problem?

I don't want to use any JS library, if it's possible without them.

Thanks for any help!

FZs
  • 14,438
  • 11
  • 35
  • 45
  • Your blocking the Javascript UI thread, so it never gets chance to update the UI. You need to do this asynchronously. – Keith Dec 17 '18 at 16:36
  • @Keith And how can I do it as async? – FZs Dec 17 '18 at 16:37
  • 1
    Possible duplicate of [Javascript progress bar not updating 'on the fly', but all-at-once once process finished?](https://stackoverflow.com/questions/5743428/javascript-progress-bar-not-updating-on-the-fly-but-all-at-once-once-process) – Herohtar Dec 17 '18 at 16:38
  • What is it your using the progress bar for, as updating the UI at say 60 fps, doing a million UI updates is going to take over 4 and half hours. – Keith Dec 17 '18 at 16:47

2 Answers2

2

You can use requestAnimationFrame:

document.getElementById("start").addEventListener("click",function(){
    var max=100;
    var p=0;
    document.getElementById("pb").max=max;
    var update = function () {
      document.getElementById("pb").value=p; 
      p++;
      if (p <= max) requestAnimationFrame(update);
      else console.log("Finished");
    };
    update();
})
<progress id="pb" value="0" max="0"></progress>
<input type="button" id="start" value="Start"/>

Or just use setTimeout and increase the timer:

document.getElementById("start").addEventListener("click",function(){
    max=100;
    document.getElementById("pb").max=max;
    for(i=0;i<max;i++){
        setTimeout(function () {
          document.getElementById("pb").value=this;
          if (this == max) console.log("Finished")
        }.bind(i+1), i*16);
    }
})
<progress id="pb" value="0" max="0"></progress>
<input type="button" id="start" value="Start"/>
rafaelcastrocouto
  • 11,128
  • 2
  • 37
  • 60
1

Here is a way of doing this async / await way,.. So you can keep your for loop.

Also notices I've reduced the max to 1000, as waiting 4 and half hours might be overkill. :)

function sleep(ms) { return new Promise((r) => 
  setTimeout(r, ms)); }
  
async function run() {
  let max=1000;
  document.getElementById("pb").max=max;
  for(let i=0;i<max;i++){
    document.getElementById("pb").value=i+1
    await sleep(0);
  }
  console.log("Finished")
}

document.getElementById("start").
  addEventListener("click", run);
<progress id="pb" value="0" max="0"></progress>
<input type="button" id="start" value="Start"/>
Keith
  • 18,130
  • 2
  • 23
  • 36