What I'm trying to do is to update a simple div to say "Processing..." before executing a CPU-intensive script (it takes 3-12 seconds to run, no AJAX) then update the div to say "Finished!" when done.
What I'm seeing is the div never gets updated with "Processing...". If I set a breakpoint immediately after that command, then the div text does get updated, so I know the syntax is correct. Same behavior in IE9, FF6, Chrome13.
Even when bypassing jQuery and using basic raw Javascript, I see the same issue.
You'd think this would have an easy answer. However, since the jQuery .html() and .text() don't have a callback hook, that's not an option. It's also not animated, so there is no .queue to manipulate.
You can test this yourselves using the sample code I prepared below that shows both the jQuery and Javascript implementations with a 5 second high-CPU function. The code is easy to follow. When you click either the button or the link, you never see "Processing..."
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js" ></script>
<script type="text/javascript">
function addSecs(d, s) {return new Date(d.valueOf()+s*1000);}
function doRun() {
document.getElementById('msg').innerHTML = 'Processing JS...';
start = new Date();
end = addSecs(start,5);
do {start = new Date();} while (end-start > 0);
document.getElementById('msg').innerHTML = 'Finished JS';
}
$(function() {
$('button').click(function(){
$('div').text('Processing JQ...');
start = new Date();
end = addSecs(start,5);
do {start = new Date();} while (end-start > 0);
$('div').text('Finished JQ');
});
});
</script>
</head>
<body>
<div id="msg">Not Started</div>
<button>jQuery</button>
<a href="#" onclick="doRun()">javascript</a>
</body>
</html>
I had to wait for jQuery to manipulate the DOM and then grap the changes (load form fields multiple times into a form, then to submit it). The DOM grew and the insertion took longer and longer. I saved the changes using ajax to have to user to be able to continue where he left off.
This did NOT WORK as intended:
Since jQuery functions like
.prepend()
do continue the chain only when done, the following seemed to do the trick:You have a loop that runs for 5 seconds and freezes the web browser during that time. Since the web browser is frozen it can't do any rendering. You should be using
setTimeout()
instead of a loop, but I'm assuming that loop is just a replacement for a CPU intensive function that takes a while? You can use setTimeout to give the browser a chance to render before executing your function:jQuery:
Vanilla JS:
You should also remember to always declare all variables using the var keyword, and avoid exposing them to the global scope. Here is a JSFiddle:
http://jsfiddle.net/Paulpro/ypQ6m/
As of 2019 one uses double
requesAnimationFrame
to skip a frame instead of creating a race condition using setTimeout.set it to processing, then do a setTimeout to prevent the cpu intensive task from running until after the div has been updated.
you can modify the setTimeout delay as needed, it may need to be larger for slower machines/browsers.
Edit:
You could also use an alert or a confirm dialog to allow the page time to update.