请看一下startTest函数,首先改变一个div样式,然后执行一段耗时的操作,可以看到startTest函数结束以后,
页面才会重新reflow和repaint,即使写成 onclick="startTest();startTest2()" 效果也依然是一样的(opera除外), 这是由javascript引擎的单线程引起的,我们知道,javascript引擎是单线程的,只有一个任务结束以后,
页面才会重新reflow和repaint,如果想要设置的样式马上生效而不想等后面那段罗嗦的代码执行完再reflow和repaint,怎么办呢?
解决方法:
只有当一个任务执行完毕之后GUI渲染线程才会执行,我们可以用setTimeout将startTest2函数排入待执行任务队列的下一个位置,这样startTest函数执行完毕以后页面会立即reflow和repaint,
我们就可以看见设置的样式生效了,而startTest2()这段罗里罗嗦的代码执行时间就排在reflow和repaint之后了,呵呵
另外,貌似opera的执行机制和其他浏览器不大一样
以上是本人的分析,不知道真实情况是不是这样的,期待有盆友能在回复中给出答案,不尽感激
关于javascript引擎单线程的特性,可以参加Rock兄的blog: http://www.bgscript.com/archives/256
里面有关的文字摘录如下:
"GUI渲染线程:
该线程负责渲染浏览器界面HTML元素,当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行.
本文虽然重点解释JavaScript定时机制,但这时有必要说说渲染线程,因为该线程与JavaScript引擎线程是互斥的,
这容易理解,因为 JavaScript脚本是可操纵DOM元素,在修改这些元素属性同时渲染界面,那么渲染线程前后获得的元素数据就可能不一致了."
”在JavaScript引擎运行脚本期间,浏览器渲染线程都是处于挂起状态的,也就是说被”冻结”了.
所以,在脚本中执行对界面进行更新操作,如添加结点,删除结点或改变结点的外观等更新并不会立即体现出来,
这些操作将保存在一个队列中,待 JavaScript引擎空闲时才有机会渲染出来.或许这里你有个疑问了,
为什么JS代码块的alert时界面有更新的,JS不是正在运行吗?其实当 alert发生时,浏览器内核就会挂起JavaScript引擎线程,并促使界面执行了更新.
“
by: 天堂左我往右
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style>
html{
border:1px solid red;
}
.div1{
width:100%;
height:500px;;
position: absolute;
background: blue;
display:none;
filter: alpha(opacity=50);
opacity:.5;
}
</style>
</head>
<body onload="" style='cursor:crosshair'>
<div id="div_1" class="div1"><img src="http://www.google.cn/logos/arborday10-hp.gif" /></div>
<input type=button value=test onclick="startTest();" />
</body>
</html>
<script>
function startTest(){
document.getElementById("div_1").style.display="block";
document.getElementById("div_1").style.height = "800px";
//这样就ok了
//setTimeout(startTest2,0);
startTest2();
}
function startTest2(){
var d1 = new Date();
var t1 = d1.getTime();
while(true){
var d2 = new Date();
var t2 = d2.getTime();
if(t2-t1>2000){
break;
}
}
alert("完毕");
}
</script>