关注互联网技术,包括交互设计、用户体验、页面设计、页面制作、前端开发。舞蹈人生!
« »
2010年06月8日前端开发

57 Views

如何优化你的脚本来减少reflow/repaint?

一、什么是repaint/reflow?

页面在加载的过程中,需要对文档结构进行解析,同时需要结合各种各样的样式来计算这个页面长什么样子,最后再经过浏览器的渲染页面就出现了。这整个 过程细说起来还是比较复杂,其中充满了repaint和reflow。对于DOM结构中的各个元素都有自己的盒子(模型),这些都需要浏览器根据各种样式 (浏览器的、开发人员定义的等)来计算并根据计算结果将元素放到它该出现的位置,这个过程称之为reflow;当各种盒子的位置、大小以及其他属性,例如 颜色、字体大小等都确定下来后,浏览器于是便把这些元素都按照各自的特性绘制了一遍,于是页面的内容出现了,这个过程称之为repaint。

如何减少浏览器的repaint和reflow?

1. 避免在document上直接进行频繁的DOM操作,如果确实需要可以采用off-document的方式进行,具体的方法包括但不完全包括以下几种:

(1). 先将元素从document中删除,完成修改后再把元素放回原来的位置

(2). 将元素的display设置为”none”,完成修改后再把display修改为原来的值

(3). 如果需要创建多个DOM节点,可以使用DocumentFragment创建完后一次性的加入document

  1. function appendEveryTime(){
  2. for( var i = 5000; i–; ){
  3. var n = document.createElement(‘div’);
  4. n.innerHTML = ’node ’ + i;
  5. document.body.appendChild(n);/*每次创建的新节点都append到文档*/
  6. }
  7. }
  8. function appendLast(){
  9. var frag = document.createDocumentFragment();
  10. for( var i = 5000; i–; ){
  11. var n = document.createElement(‘div’);
  12. n.innerHTML = ’node ’ + i;
  13. frag.appendChild(n);/*每次创建的节点先放入DocumentFragment中*/
  14. }
  15. document.body.appendChild(frag);
  16. }
function appendEveryTime(){
    for( var i = 5000; i--; ){
        var n = document.createElement('div');
        n.innerHTML = 'node ' + i;
        document.body.appendChild(n);/*每次创建的新节点都append到文档*/
    }
}

function appendLast(){
     var frag = document.createDocumentFragment();
     for( var i = 5000; i--; ){
         var n = document.createElement('div');
         n.innerHTML = 'node ' + i;
         frag.appendChild(n);/*每次创建的节点先放入DocumentFragment中*/
     }
     document.body.appendChild(frag);
}

用dynaTrace观察的结果如下,appendLast的性能无论是在Javascript的执行时间以及浏览器渲染时间方面都优于appendEveryTime。

appendEveryTime:

image

appendLast:

image

2. 集中修改样式

(1). 尽可能少的修改元素style上的属性

(2). 尽量通过修改className来修改样式

(3). 通过cssText属性来设置样式值

如下的代码中,每一次赋值都会造成浏览器重新渲染,可以采用cssText或者className的方式

  1. el.style.color = ’red;
  2. el.style.height = ’100px’;
  3. el.style.fontSize = ’12px’;
  4. el.style.backgroundColor = ’white’;
el.style.color = 'red;
el.style.height = '100px';
el.style.fontSize = '12px';
el.style.backgroundColor = 'white';

3. 缓存Layout属性值

对于Layout属性中非引用类型的值(数字型),如果需要多次访问则可以在一次访问时先存储到局部变量中,之后都使用局部变量,这样可以避免每次读取属性时造成浏览器的渲染。

  1. var width = el.offsetWidth;
  2. var scrollLeft = el.scrollLeft;
var width = el.offsetWidth;
var scrollLeft = el.scrollLeft;

4. 设置元素的position为absolute或fixed

在元素的position为static和relative时,元素处于DOM树结构当中,当对元素的某个操作需要重新渲染时,浏览器会渲染整个页 面。将元素的position设置为absolute和fixed可以使元素从DOM树结构中脱离出来独立的存在,而浏览器在需要渲染时只需要渲染该元素 以及位于该元素下方的元素,从而在某种程度上缩短浏览器渲染时间,这在当今越来越多的Javascript动画方面尤其值得考虑。

  1. <body style=”position:relative”>
  2. <div id=”test” style=”background-color:red;width:100px;position:relative;”>Animation Here</div>
  3. </body>
  4. <script type=”text/javascript”>
  5. function $(id){
  6. return document.getElementById(id);
  7. }
  8. window.onload = function(){
  9. var t = $(‘test’);
  10. ~function(){
  11. tt.style.left = t.offsetLeft + 5 + ’px’;
  12. tt.style.height = t.offsetHeight + 5 + ’px’;
  13. setTimeout(arguments.callee,500);
  14. }();
  15. }
  16. </script>
<body style="position:relative">
	<div id="test" style="background-color:red;width:100px;position:relative;">Animation Here</div>
</body>
<script type="text/javascript">
	function $(id){
		return document.getElementById(id);
	}
	window.onload = function(){
		var t = $('test');

		~function(){
			t.style.left = t.offsetLeft + 5 + 'px';
			t.style.height = t.offsetHeight + 5 + 'px';
			setTimeout(arguments.callee,500);
		}();
	}
</script>

通过修改#test元素的postion为relative和postion分别得到如下两个测试结果

position: relative

image

position: absolute

image

在postion:relative的测试当中,浏览器在重新渲染时做的工作比position:absolute多了不少。

参考资料

Understanding Internet Explorer Rendering Behaviour

Notes on HTML Reflow

EFFICIENT JAVASCRIPT

来源:http://varnow.org/?p=232

日志信息 »

该日志于2010-06-08 15:12由 虎大誌 发表在前端开发分类下, 你可以发表评论。除了可以将这个日志以保留源地址及作者的情况下引用到你的网站或博客,还可以通过RSS 2.0订阅这个日志的所有评论。

相关日志 »

  • 暂无相关日志

没有评论

发表评论 »

返回顶部