Skip to content Skip to sidebar Skip to footer

Update Webpage To Show Progress While Javascript Is Running In In A Loop

I have written javascript that takes 20-30 seconds to process and I want to show the progress by updating the progress bar on my webpage. I have used setTimeout in an attempt to al

Solution 1:

As you probably know, the problem here is that you main process (the one that takes a lot of time), is blocking any rendering. That's because JavaScript is (mostly) mono-threaded.

From my point of view, you have two solutions to do this. The first one is to cut down your main process into different parts and to do the rendering between each of them. I.e. you could have something like that (using Promises) :

var processParts = [/* array of func returning promises */];

functionstart(){
    // call the first process partsvar firstPartPromise = (processParts.shift())();
    // chain it with all the other process parts interspersed by updateDisplayreturn processParts.reduce(function(prev, current){
        return val.then(current).then(updateDisplay);
    }, firstPartPromise);
}

You will probably need a polyfill for the promises (one here). If you use jQuery, they have a (bad non standard) implementation.

The second solution can be to use webworkers which allows you to create threads in JavaScript. It works on all modern browsers. It is probably the best solution in your case. I never used them but you are supposed to be able to do stuff like:

var process = new Worker("process.js");

worker.onmessage(function(event){
    updateProgress(event.data.progress)
});

And the in process.js:

postMessage({progress: 0.1});
// stuffpostMessage({progress: 0.4});
// stuffpostMessage({progress: 0.7});
//etc

Solution 2:

Try setting progress element attribute min to 0 , max to 20000 , value to 0 ; create function where if value less than max increment value by 1000 ; utilize setTimeout with duration set to 1000 to call function recursively until value reaches max

var p = document.querySelector("progress");

functionredraw() {
   if (p.value < p.max) {
     p.value += 1000;
     setTimeout("redraw()", 1000)
   }
}

redraw()
<progressmax="20000"min="0"value="0"></progress>

Solution 3:

There are a couple of ways that I know of to trigger sequential HTML redraws through Javascript:

  • Incremental Timeout Period
  • Recursive Method Calls

The first and easiest way of doing this is by using a multiplier (such as the iterator) on the timeout interval in a loop. This method should be sufficient if the operation is independent of external variables and only needs to be run a finite and relatively few number of times. The more operations required/likely to occur, the greater the strain on resources - just for calculating intervals. Another drawback takes effect when the processing time exceeds the timeout interval, causing a knock-on to the interval of the observed redraws. The result of this can be that the web page freezes up entirely until all operations are done.

Example

for (var i=0, limit=n; i<limit; i++) {
    setTimeout((function(params) {
        return  function() {
            some_func(params);
        }
    })(param_values), i*1000);
}

The second method is a little more convoluted, but guarantees redraws between each operation, regardless of the timeout interval. Here, the timeout only affects the time between redraws ands resists the effects of consecutive operation variables. However, the processing time for the current operation is still a factor for the observed interval and will still freeze up a web page between redraws if the operation is computationally intensive.

Example

var limit = n;
var i = 0;
recursive_timeout();
functionrecursive_timeout() {
    setTimeout((function(params) {
        returnfunction() {
            some_func(params);
            i++;
            if (i<limit) {
                recursive_timeout();
            }
        }
    })(param_values, i, limit), 1000);
}

Refined Example (based off guest271314's answer)

var still_true = true;
recursive_timeout();
functionrecursive_timeout() {
    some_func(params);
    if (still_true) {
        setTimeout(function() {recursive_timeout();}, 1000);
    }
}

While the incremental method is fine for simple tasks, recursion will reliably perform redraws. If long processing times per operation is an issue, then it might be worth delving into asynchronous tasks in addition to using recursion in order to avoid rendering a web page temporarily unusable.

Anyway, hope this helps!

Ha! Just realised guest271314 put up a much more elegant example of the recursive method... Oh well, more info can't hurt.

Post a Comment for "Update Webpage To Show Progress While Javascript Is Running In In A Loop"