What I am trying to achieve:
You need to either wait a millisecond or do the calculations with a Worker.
The first example is probably the easiest, instead of calling calc
directly, create a new function
function caller() {
// insert "calculation in progress" in the body
setTimeout(calc, 1);
}
Then call caller
.
IMO an easy way to handle this is to have your computation performed in "small" chunks by a timer function, for example:
function calcFractal(x0, y0, x1, y1) {
... compute the fractal for the tile (x0, y0)-(x1, y1) ...
}
var x = 0, y = 0;
function nextTile() {
calcFractal(x, y, x+tw, y+th);
x += tw;
if (x >= width) {
x = 0;
y += th;
}
if (y < height) setTimeout(nextTile, 0);
}
nextTile();
This allows you to show progress (including for example a low resolution of the fractal, the percentage of the computation) and to allow interruption (with onclick
events on a stop button for example).
If the tiles are not tiny the overhead will be acceptable, still maintaining the page reasonably responsive to both repaints and user interaction.
Because modern browsers may delay redrawing for better frame rate, versions with setTimeout
may not work with too low time-outs.
If possible you need to use requestAnimationFrame. If its not posible then @Bálint answer should work, but with much bigger timeout (in my tests in Firefox its began work with timeout near 20-30). Actual timeout value is browser dependent (and probably system dependent too)
function very_long_func(){
el= document.getElementById('di');
requestAnimationFrame( function(){
//edit dom for new frame;
el.textContent = 'calculation in progress'
//browser will wait for this functions end, before start redraw.
//So actual calucation must run outside of it
setTimeout( function_with_actual_calculation, 1 );
})
}
function function_with_actual_calculation(){
//..your math here + updating textContent to "done" in the end.
}