0

I'm trying to create a progress bar using an HTML canvas to show the progress of a computationally-intensive loop in javascript. The problem I'm having is that the canvas doesn't actually update until the entire loop is finished.

I know that the calculation loop is working, and by inserting an alert into the loop, I have determined that the code to update the progress bar works. It seems that the browser simply waits to update the canvas until the entire calculation loop is done (which, of course, defeats the purpose of a progress bar).

I have tried

  1. Simply calling the progress-bar-updating function in the calculation loop
  2. Calling the progress-bar-updating function via repeated window.setTimeout calls during the loop
  3. Calling the progress-bar-updating function by scheduling a window.setInterval event before the loop starts.

But to no effect - the progress bar remains empty until the calculation loop ends, then instantly jumps to full.

Here is a stripped-down version of my code. I've tried to show all three solutions at the same time (of course, I only implemented one of the three at a time):

function calculateStuff(progressCallback) {
    var x = 0, y = 0;
    var total = N[0]*N[1];

    // Solution #3: Schedule repeated calls using setInterval
    // var intervalID = window.setInterval(progressCallback, 0, N[0]*y/total);

    for (y = 0; y < N[1]; y++) {
        for (x = 0; x < N[0]; x++) {
            // Do computationally-intensive stuff here
        }
//      Solution #1 - Just directly call the progress bar updater during the loop
//      progressCallback(N[0]*y/total);
//      Solution #2 - Schedule a progress bar update using setTimeout
//      window.setTimeout(progressCallback, 0, N[0]*y/total);
    }

//  Solution #1:
//  progressCallback(N[0]*y/total);
//  Solution #3:
//  window.clearInterval(intervalID)
    return resultOfComputation;
}

function setProgress(f) {
//  Input: f - float between 0 and 1 indicating progress
//  Setting off an alert allow me to see that this function does in fact update the progress bar.
//  alert("Progress!");
    progressCtx.clearRect(0, 0, progressCanvas.width, progressCanvas.height);
    progressCtx.fillStyle = "blue";
    progressCtx.fillRect(0, 0, progressCanvas.width * f, progressCanvas.height);
}

var result = calculateStuff(setProgress);

For the record, I've read the following questions that seemed like duplicates: this and this and this, but none of those solutions seem to work.

Thanks for any help!

Community
  • 1
  • 1
Brionius
  • 13,858
  • 3
  • 38
  • 49
  • 1
    What about [web workers](https://developer.mozilla.org/en-US/docs/Web/API/Worker) to "out-source" the computational stuff? [Using Web Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers), [An HTML5 ProgressBar using Web Workers](http://www.codeproject.com/Articles/250102/An-HTML-progressbar-using-web-workers) – Andreas Dec 26 '15 at 14:43
  • Javascript is single threaded. It can not run your calculations and execute the timer events. You have to either do your calculations in smaller bits and give the execution stack a chance to call the timer – Blindman67 Dec 26 '15 at 14:43
  • @Blindman67 I agree, but since it's single threaded, when I attempt solution #1, why doesn't the calculation loop stop while the canvas update code runs? That's what I expected to happen. – Brionius Dec 26 '15 at 14:51
  • @Andreas Thanks for the link about web workers. It looks like it addresses a similar situation to mine, so I'll give it a try. I am a bit put off that it takes this special `Worker` class to accomplish this, but if it works, I'll live with it. – Brionius Dec 26 '15 at 14:54
  • @Brionius Because when a function executes it blocks all code until it has exited. This ensures that the current execution state remains consistent. Andreas solution is the best way to handle this type of situation. – Blindman67 Dec 26 '15 at 15:08
  • Thanks for your replies - perhaps I'm missing something, but when I call `progressCallback(N[0]*y/total)` why does that not "block all code until `progressCallback` has exited", then go back to the computation loop? As far as I can tell, it does the exact opposite of what you're claiming - it does NOT stop the computation loop while it updates the progress canvas, but instead just continues on with the loop. Again, I must be misunderstanding something - could you or someone help me understand what it is? – Brionius Dec 26 '15 at 15:49
  • Can you provide a fiddle? – sujit Dec 26 '15 at 18:02

0 Answers0