浏览器呈现和javascript执行的同步/异步特性

我有一些处理需要几秒钟,所以我想在它正在进行时添加一个可视指示器。

.processing { background-color: #ff0000; } 
Processing

脚本:

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

我天真地认为该类将应用于div并且UI将被更新。 但是,在浏览器中运行它(至少在Firefox中),div永远不会突出显示。 有人可以向我解释为什么我的div永远不会突出显示? 添加该类,进行处理,然后删除该类; UI不会在两者之间更新,用户永远不会看到红色背景。

我知道JS是单线程的,但我总是假设浏览器渲染会在DOM更新时同步运行。 我的假设不正确吗?

更重要的是,实现这种效果的推荐方法是什么? 我是否必须使用setTimeout使慢速处理异步并使用回调? 必须有更好的方法,因为我真的不需要异步行为; 我只想要UI刷新。

编辑:

JSFiddle: http : //jsfiddle.net/SE8wD/5/

(注意,您可能需要调整循环迭代次数,以便在您自己的PC上为您提供合理的延迟)

我不建议冻结浏览器的重量脚本。 在这种情况下,我更喜欢更改不冻结浏览器和DOM的代码。 如果在你的代码中有一些循环,你可以调用一个具有延迟的函数(使用setInterval)并在某处存储一些状态变量。 例如:

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

可:

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

或类似和更优化的东西。 你的代码会更复杂,速度更慢...... 但是,这样可以防止浏览器冻结,并且可以创建高级预加载状态栏。

你可能应该把处理放在一个单独的事件中,像这样;

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

这样浏览器应该通过processing重绘屏幕,而长时间运行的步骤将作为单独的事件启动,并在完成后删除处理消息。

浏览器在重新绘制和何时重排时非常自由。 不同的引擎会显示不同的行为。 有关进一步阅读,请参阅DOM环境中何时进行重排? 。 在您的示例中,浏览器会看到您添加一个类并在此之后直接删除它,因此他可能不会执行任何可见的操作。

为了避免这种情况,您可以应用强制重绘,或者使计算与WebWorkers或setTimeout等异步。

强制重绘 。 或者,使用Soren的代码,因为UI线程上的处理听起来很糟糕……