最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

jquery - Synchronousasynchronous nature of browser rendering and javascript execution - Stack Overflow

programmeradmin0浏览0评论

I have some processing that is going to take a few seconds so I want to add a visual indicator while it is in progress.

.processing
{
  background-color: #ff0000;
}

<div id="mydiv">
  Processing
</div>

Script:

$("#mydiv").addClass("processing");
// Do some long running processing
$("#mydiv").removeClass("processing");

I naively thought that the class would be applied to the div and the UI would be updated. However, running this in the browser (in Firefox at least) the div is never highlighted. Can someone explain to me why my my div never gets highlighted? The class is added, the processing takes place and then the class is removed; the UI is not updated in between and the user never sees the red background.

I know JS is single-threaded but I'd always presumed the browser rendering would run synchronously as and when the DOM is updated. Is my assumption incorrect?

And more importantly, what is the remended way to achieve this effect? Do I have to result to using setTimeout to make the slow processing asynchronous and work with a callback? There must be a better way as I really don't have any need for async behaviour here; I just want the UI to refresh.

EDIT:

JSFiddle: /

(Note, you may need to tweak the number of loop iterations to give you a reasonable delay on your own PC)

I have some processing that is going to take a few seconds so I want to add a visual indicator while it is in progress.

.processing
{
  background-color: #ff0000;
}

<div id="mydiv">
  Processing
</div>

Script:

$("#mydiv").addClass("processing");
// Do some long running processing
$("#mydiv").removeClass("processing");

I naively thought that the class would be applied to the div and the UI would be updated. However, running this in the browser (in Firefox at least) the div is never highlighted. Can someone explain to me why my my div never gets highlighted? The class is added, the processing takes place and then the class is removed; the UI is not updated in between and the user never sees the red background.

I know JS is single-threaded but I'd always presumed the browser rendering would run synchronously as and when the DOM is updated. Is my assumption incorrect?

And more importantly, what is the remended way to achieve this effect? Do I have to result to using setTimeout to make the slow processing asynchronous and work with a callback? There must be a better way as I really don't have any need for async behaviour here; I just want the UI to refresh.

EDIT:

JSFiddle: http://jsfiddle/SE8wD/5/

(Note, you may need to tweak the number of loop iterations to give you a reasonable delay on your own PC)

Share edited Mar 23, 2012 at 13:14 njr101 asked Mar 23, 2012 at 10:55 njr101njr101 9,6297 gold badges41 silver badges56 bronze badges 8
  • 1 I believe such changes will make it directly to the DOM, but the browser will wait until the JavaScript execution is "idle" before doing any repainting. – pimvdb Commented Mar 23, 2012 at 10:58
  • "Do some long running processing" has some asynchronous call? (ajax, settimeout etc) – Luca Rainone Commented Mar 23, 2012 at 11:00
  • I can't really see where your code goes wrong, because it seems fine of what you have posted. Maybe there is some !important in your external css file. Are you sure the class get's added ( have you inspected it via firebug) and does the process really take that long ? maybe it happens too fast – mas-designs Commented Mar 23, 2012 at 11:00
  • @chumkiu havin an ajax or settimout in his code will not work because the add and remove will not wait for the asynchronous to finish ! – mas-designs Commented Mar 23, 2012 at 11:01
  • @EvilP exactly. His assumptions is correct, so there is something of wrong somewhere else – Luca Rainone Commented Mar 23, 2012 at 11:05
 |  Show 3 more ments

4 Answers 4

Reset to default 2

You probably should put the processing out in a seperate event, like this;

$("#mydiv").addClass("processing");
setTimeout(function(){
   // This runs as a seperate event after
   // Do some long running processing
   $("#mydiv").removeClass("processing");
},1);

That way the browser should redraw the screen with the processing, while the long running step will kick off as a seperate event, and remove the processing message when done.

I not remend to freeze browser for a weight script. In this case I prefer to change the code for not freeze browser and DOM. If in your code there is some loop, you can call a function with a delay (using setInterval) and store some status variable somewhere. For example:

for(var i=0; i<1000000; i++) {
    // do something
}

Can be:

var i = 0;
var intervalID;
var _f = function() {
    // do something
    i++;
    if(i==1000000) clearInterval(intervalID);
}
intervalID  = setInterval(_f,1);

Or something of similar and more optimized. Your code will be a little bit more plex, and slower.. . but so you prevent browser freeze and you can make an advanced preload status bar.

A browser is quite free about when to repaint and when to reflow. Different engines will show different behavior. For further reading, see When does reflow happen in a DOM environment?. In your example, the browser sees you adding a class and removing it directly after that, so he might not do anything visible.

To avoid that, you may apply a force-redraw-hack, or make your putation asynchronous with WebWorkers or setTimeout or something.

Force a redraw. Alternatively, use Soren's code because processing on the UI thread sounds bad...

发布评论

评论列表(0)

  1. 暂无评论