文本内容主要包括以下几点:
- 什么是repaint/reflow?
- 什么情况下会触发浏览器的repaint/reflow?
- 浏览器自身所作的优化
- 如何优化你的脚本来减少repaint/reflow?
一、什么是repaint/reflow?
页面在加载的过程中,需要对文档结构进行解析,同时需要结合各种各样的样式来计算这个页面长什么样子,最后再经过浏览器的渲染页面就出现了。这整个 过程细说起来还是比较复杂,其中充满了repaint和reflow。对于DOM结构中的各个元素都有自己的盒子(模型),这些都需要浏览器根据各种样式 (浏览器的、开发人员定义的等)来计算并根据计算结果将元素放到它该出现的位置,这个过程称之为reflow;当各种盒子的位置、大小以及其他属性,例如 颜色、字体大小等都确定下来后,浏览器于是便把这些元素都按照各自的特性绘制了一遍,于是页面的内容出现了,这个过程称之为repaint。
以上提到的只是在页面加载时必然会出现的repaint和reflow,除此之外,在页面加载完成后,用户的一些操作、脚本的一些操作都会导致浏览器发生这种行为,具体在后文阐述。
另外,关于浏览器渲染的更为详细的资料可以参考以下,涵盖了IE以及Firefox:
Understanding Internet Explorer Rendering Behaviour
二、什么情况下会触发浏览器的repaint/reflow?
除了页面在首次加载时必然要经历该过程之外,还有以下行为会触发这个行为:
- DOM元素的添加、修改(内容)、删除( Reflow + Repaint)
- 仅修改DOM元素的字体颜色(只有Repaint,因为不需要调整布局)
- 应用新的样式或者修改任何影响元素外观的属性
- Resize浏览器窗口、滚动页面
- 读取元素的某些属性(offsetLeft、offsetTop、offsetHeight、offsetWidth、 scrollTop/Left/Width/Height、clientTop/Left/Width/Height、 getComputedStyle()、currentStyle(in IE))
在继续下面的文章之前,先介绍一款强大的性能分析工具-dynaTrace,借助该功能能够清晰的得到页面中的资源消耗情况,从而对症下药。另外,更细节的方面是它可以跟踪每个函数调用所造成的CPU消耗、Repaint/Reflow。接下来就借助该工具来测试一下以上描述的几点情况。
DOM元素的增删改
先看代码
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3c.org/TR/html4/strict.dtd">
- <html>
- <body>
- <div id="test1" onclick="addNode()">这里是第1个节点</div>
- <div id="test2" onclick="modNode()">这里是第2个节点</div>
- <div id="test3" onclick="delNode()">这里是第3个节点</div>
- </body>
- <script type="text/javascript">
- function $(id){
- return document.getElementById(id);
- }
- function addNode(){
- var n = document.createElement('div');
- n.innerHTML = 'New Node';
- $('test1').appendChild(n);
- }
- function modNode(){
- $('test2').innerHTML = 'hello';
- }
- function delNode(){
- $('test3').parentNode.removeChild($('test3'));
- }
- </script>
- </html>
在依次点击完每一个按钮后,我们来看看dynaTrace的情况,首先是一目了然的点击事件分布
放大之后来看一下每个事件的repaint/reflow情况:
增加节点:
修改节点:
删除节点:
图中的绿色部分表示的是reflow和repaint过程,其中比较短的绿条标示的reflow过程,后面长条部分表示 的是repaint过程。从图中可以看出,对DOM节点的增删改都会造成reflow和repaint,由于改动小所以reflow消耗的时间很短,但是 由于repaint是全局的,因此消耗的时间都比较长。
修改DOM元素前景色
- var n = $('colorNode');
- n.style.color = 'red';
从上图中可以看到修改字体颜色后,浏览器只有repaint而没有reflow。接下来试试修改背景色:
- var n = $('colorNode');
- n.style.backgroundColor = 'red';
由图中可以看出,修改背景色也会造成reflow和repaint。另外,经过测试发现,只要是修改元素的cssText属性,不论它的值是什么,都会导致浏览器reflow和repaint,因此在某些时候选择特定的样式属性赋值会有更好的效果。
Resize浏览器窗口以及拖动滚动条
测试中的操作如下:缩小浏览器窗口->放大浏览器窗口->拖动页面滚动条至页面底部。从图中可以看到Resize浏览器窗口以及拖动滚动条都会造成浏览器的repaint,而且CPU的消耗也比较大,尤其是拖动滚动条的时候。
读取Layout属性
根据各种参考资料中的描述,在用Javascript读取DOM节点的Layout属性(offsetLeft、offsetTop、 offsetHeight、offsetWidth、scrollTop/Left/Width/Height、clientTop/Left /Width/Height、getComputedStyle()、currentStyle(in IE)) 的时候也会触发repaint,不过在以下的测试例子中并没有发现这一点。
- var n = $('colorNode');
- var temp = document.documentElement.currentStyle;
- temp = n.offsetTop;
- temp = n.offsetLeft;
- temp = n.offsetWidth;
- temp = n.offsetHeight;
- temp = n.scrollTop;
- temp = n.scrollHeight;
- alert(temp);
三、浏览器优化
浏览器对于每一个渲染动作并不是立即执行,而是维护了一个渲染任务队列,浏览器会根据具体的需要分批集中执行其中的任务。除了浏览器自身维护的定期调度之外,脚本中的某些操作会导致浏览器立即执行渲染任务,例如读取元素的Layout属性。
- var bodystyle = document.body.style;
- var computed;
- if (document.body.currentStyle) {
- computed = document.body.currentStyle;
- } else {
- computed = document.defaultView.getComputedStyle(document.body, '');
- }
- //每次都读取
- bodystyle.color = 'red';
- bodystyle.padding = '1px';
- tmp = computed.backgroundColor;
- bodystyle.color = 'white';
- bodystyle.padding = '2px';
- tmp = computed.backgroundImage;
- bodystyle.color = 'green';
- bodystyle.padding = '3px';
- tmp = computed.backgroundAttachment;
- //最后再读取
- bodystyle.color = 'yellow';
- bodystyle.padding = '4px';
- bodystyle.color = 'pink';
- bodystyle.padding = '5px';
- bodystyle.color = 'blue';
- bodystyle.padding = '6px';
- tmp = computed.backgroundColor;
- tmp = computed.backgroundImage;
- tmp = computed.backgroundAttachment;
每次读取的渲染图:
最后读取的渲染图:
四、如何优化你的脚本来减少reflow/repaint?
1. 避免在document上直接进行频繁的DOM操作,如果确实需要可以采用off-document的方式进行,具体的方法包括但不完全包括以下几种:
(1). 先将元素从document中删除,完成修改后再把元素放回原来的位置
(2). 将元素的display设置为”none”,完成修改后再把display修改为原来的值
(3). 如果需要创建多个DOM节点,可以使用DocumentFragment创建完后一次性的加入document
- 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:
appendLast:
2. 集中修改样式
(1). 尽可能少的修改元素style上的属性
(2). 尽量通过修改className来修改样式
(3). 通过cssText属性来设置样式值
如下的代码中,每一次赋值都会造成浏览器重新渲染,可以采用cssText或者className的方式
- el.style.color = 'red;
- el.style.height = '100px';
- el.style.fontSize = '12px';
- el.style.backgroundColor = 'white';
3. 缓存Layout属性值
对于Layout属性中非引用类型的值(数字型),如果需要多次访问则可以在一次访问时先存储到局部变量中,之后都使用局部变量,这样可以避免每次读取属性时造成浏览器的渲染。
- var width = el.offsetWidth;
- var scrollLeft = el.scrollLeft;
4. 设置元素的position为absolute或fixed
在元素的position为static和relative时,元素处于DOM树结构当中,当对元素的某个操作需要重新渲染时,浏览器会渲染整个页 面。将元素的position设置为absolute和fixed可以使元素从DOM树结构中脱离出来独立的存在,而浏览器在需要渲染时只需要渲染该元素 以及位于该元素下方的元素,从而在某种程度上缩短浏览器渲染时间,这在当今越来越多的Javascript动画方面尤其值得考虑。
- <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(){
- tt.style.left = t.offsetLeft + 5 + 'px';
- tt.style.height = t.offsetHeight + 5 + 'px';
- setTimeout(arguments.callee,500);
- }();
- }
- </script>
通过修改#test元素的postion为relative和postion分别得到如下两个测试结果
position: relative
position: absolute
在postion:relative的测试当中,浏览器在重新渲染时做的工作比position:absolute多了不少。
参考资料
Understanding Internet Explorer Rendering Behaviour
原文地址 http://varnow.org/?p=232
发表评论
-
基于脚本的动画的计时控制(“requestAnimationFrame”)(转载)
2014-03-04 19:12 930Internet Explorer 10 和使 ... -
IE11开发人员工具:UI响应工具详解
2014-02-27 18:33 880我讨厌debug,相信也没多少开发者会喜欢。但是当代码出 ... -
IE11开发人员工具:内存分析工具详解
2014-02-27 18:32 1363上篇我们跟大家介绍 ... -
E6与location.hash和Ajax历史记录 (转载)
2014-02-26 12:23 510为了在IE6中改变hash来保留历史记录实现ajax的前进 ... -
MIME Types(转载)
2013-12-31 10:20 599MIME Types - Complete List ... -
iframe历史记录问题(转载)
2013-10-17 10:21 1242在做页面统计的时候 ... -
前端类库精选(转)
2013-05-11 00:57 0优秀的前端类库,自己平时遇见了,这里Mark一下。 1、m ... -
10个chrome console实用小技巧(转)
2013-05-09 10:56 10131. 基本输出 让我们先从最常见的console.l ... -
CSS3那些不为人知的高级属性(转)
2013-04-19 13:35 890原文:CSS的未来:一些 ... -
JavaScript 时间、格式、转换及Date对象总结(转)
2013-04-10 14:49 677悲剧的遇到问题,从前台得到时间,“Tue Jan 29 16 ... -
如何制作一个可及性强(accessible)的网页弹框(转载)
2013-04-02 16:18 775英文原文:Making an accessib ... -
JavaScript MVC js也mvc(转载)
2013-03-16 23:59 661JavaScript MVC 中文:http://blog ... -
SUBLIME TEXT 2 设置文件详解
2012-12-27 11:21 1013Sublime Text 2是那种让人会一眼就爱上的编辑 ... -
两个按位非操作与Math.floor操作(译)
2012-12-10 18:17 913位操作符在我们编码过程中是容易被遗忘的,可能更多的源于我们 ... -
img中src为空的影响
2012-11-26 23:32 0这是我们经常能遇到的代码,可以直接用html标签或者Java ... -
IE6下position定位子元素溢出,父元素被撑开的解决思路。(转)
2012-11-13 18:04 1598在一些被常规的页面布局当中,我们常常需要通过positi ... -
chrome developer tool 调试技巧(转)
2012-11-12 13:16 805这篇文章是根据目前 chrome 稳定版(19.0.10 ... -
你清楚jquery是如何清除ajax缓存的吗?(转)
2012-11-11 11:19 1018大家都知道万恶的IE在ajax中往往只读取第一次ajax ... -
是时候使用JavaScript严谨模式(Strict Mode)提升团队开发效率 In JavaScript(转)
2012-11-10 23:33 678随着WebApp突飞猛进的发展,Javascript写的 ... -
Javascript基础
2012-11-10 23:25 0原文:http://bonsaiden.githu ...
相关推荐
本文主要是结合自己的一些项目经验,给大家提出了几点减少浏览器reflow和repaint的方法和注意事项,希望对大家能有所帮助。
等这些忠告,以前我就大概知道使用通配符或者CSS选择器层次过多可能会降低性能,至于为什么不使用table标签我一直是迷迷糊糊,也就跟着那样做了,但我认识了Repain和 Reflow之后,原来这些还真不能用太多。...
1. 浏览器渲染机制 2. 重绘 3. 回流 4. 浏览器优化 5. 减少重绘与回流
本篇文章,小编将为大家介绍,有关javascript的性能优化(repaint和reflow),有需要的朋友可以参考一下
Graphics 与 repaint 方法
qt 中更新界面和重绘的问题
hill no repaint for mt4
this indicator to optimized analyse forex trading for all pair and any time frame
导致js效率低的两个因素都包括在内了在频繁的操作DOM和CSS时,浏览器会不停的执行重排和重绘,在PC版本的浏览器中,因为浏览器可用的内存比较大,用户肉眼几乎看不见页面动画产生的repaint和reflow,所以工程师几乎...
其中面试的时候经常会问到的回流(重排reflow)和重绘(repaint)也是出在这个渲染流程里,下面来逐个步骤的说明讲解。 一、构建DOM树(DOMTree) 我们知道,浏览器是无法直接理解和使用HTML的,为了能让浏览器理解...
Java中Graphics的paint和repaint方法.pdf 学习资料 复习资料 教学资源
Indicator for mt4 no repaint
1、 JavaScript 的基本类型有哪些?引用类型有哪些?null 和 undefined 的区别?...30、如何最小化重绘(repaint)和回流(reflow)(高薪常问) 120 31、Js 延迟加载的方式有哪些?(了解) 120 32、IE 与
对于轻量级和重量级组件的区别,和repaint函数中重量级组件打的处理
R196 Spider_Options no repaint
解析HTML,CSS,将它们组合在一起,然后计算所有元素...例子存储库提供了一个简单的界面,用于使用repaint编辑和渲染markdown和HTML。 通过首先将markdown转换为纯HTML来呈现。 减价格式化的自述文件 markdown带有图像
script src =" dist/repaint.min.js " > </ script > < script > jQuery ( function ( $ ) { $ ( '*' ) . repaint ( ) ; // "awesome" } ) ; </ script > 执照 麻省理工学院 :copyright: ...