我有一些处理需要几秒钟,所以我想在它正在进行时添加一个可视指示器。
.processing
{
background-color: #ff0000;
}
<div id="mydiv">
Processing
</div>
脚本:
$("#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上为您提供合理的延迟)
答案 0 :(得分:1)
我不建议冻结浏览器以获取权重脚本。 在这种情况下,我更喜欢更改不冻结浏览器和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);
或类似且更优化的东西。 你的代码会更复杂,速度更慢......但是你要阻止浏览器冻结,你可以制作一个高级的预加载状态栏。
答案 1 :(得分:1)
你可能应该把处理放在一个单独的事件中,像这样;
$("#mydiv").addClass("processing");
setTimeout(function(){
// This runs as a seperate event after
// Do some long running processing
$("#mydiv").removeClass("processing");
},1);
这样浏览器应该使用processing
重绘屏幕,而长时间运行的步骤将作为单独的事件启动,并在完成后删除处理消息。
答案 2 :(得分:0)
Force a redraw。或者,使用Soren's code,因为UI线程上的处理听起来很糟糕......
答案 3 :(得分:0)
浏览器在重绘和何时重排时非常自由。不同的引擎会显示不同的行为。如需进一步阅读,请参阅When does reflow happen in a DOM environment?。在您的示例中,浏览器会看到您添加一个类并在此之后直接删除它,因此他可能不会执行任何可见的操作。
为避免这种情况,您可以应用强制重绘,或者使计算与WebWorkers或setTimeout等异步。