`

如何减少浏览器的repaint和reflow?(转载)

阅读更多

文本内容主要包括以下几点:

  1. 什么是repaint/reflow?
  2. 什么情况下会触发浏览器的repaint/reflow?
  3. 浏览器自身所作的优化
  4. 如何优化你的脚本来减少repaint/reflow?

 

一、什么是repaint/reflow?

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

以上提到的只是在页面加载时必然会出现的repaint和reflow,除此之外,在页面加载完成后,用户的一些操作、脚本的一些操作都会导致浏览器发生这种行为,具体在后文阐述。

另外,关于浏览器渲染的更为详细的资料可以参考以下,涵盖了IE以及Firefox:

Understanding Internet Explorer Rendering Behaviour

Notes on HTML Reflow

二、什么情况下会触发浏览器的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元素的增删改

先看代码

  1. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3c.org/TR/html4/strict.dtd">  
  2. <html>  
  3.     <body>  
  4.         <div id="test1" onclick="addNode()">这里是第1个节点</div>  
  5.         <div id="test2" onclick="modNode()">这里是第2个节点</div>  
  6.         <div id="test3" onclick="delNode()">这里是第3个节点</div>  
  7.     </body>  
  8.     <script type="text/javascript">  
  9.         function $(id){  
  10.             return document.getElementById(id);  
  11.         }  
  12.         function addNode(){  
  13.             var n = document.createElement('div');  
  14.             n.innerHTML = 'New Node';  
  15.             $('test1').appendChild(n);  
  16.         }  
  17.         function modNode(){  
  18.             $('test2').innerHTML = 'hello';  
  19.         }  
  20.         function delNode(){  
  21.             $('test3').parentNode.removeChild($('test3'));  
  22.         }  
  23.     </script>  
  24. </html>  

在依次点击完每一个按钮后,我们来看看dynaTrace的情况,首先是一目了然的点击事件分布

image

放大之后来看一下每个事件的repaint/reflow情况:

增加节点:

image

修改节点:

image

删除节点:

image

图中的绿色部分表示的是reflow和repaint过程,其中比较短的绿条标示的reflow过程,后面长条部分表示 的是repaint过程。从图中可以看出,对DOM节点的增删改都会造成reflow和repaint,由于改动小所以reflow消耗的时间很短,但是 由于repaint是全局的,因此消耗的时间都比较长。

修改DOM元素前景色
  1. var n = $('colorNode');  
  2. n.style.color = 'red';  

image

从上图中可以看到修改字体颜色后,浏览器只有repaint而没有reflow。接下来试试修改背景色:

  1. var n = $('colorNode');  
  2. n.style.backgroundColor = 'red';  

image

由图中可以看出,修改背景色也会造成reflow和repaint。另外,经过测试发现,只要是修改元素的cssText属性,不论它的值是什么,都会导致浏览器reflow和repaint,因此在某些时候选择特定的样式属性赋值会有更好的效果。

Resize浏览器窗口以及拖动滚动条

image

测试中的操作如下:缩小浏览器窗口->放大浏览器窗口->拖动页面滚动条至页面底部。从图中可以看到Resize浏览器窗口以及拖动滚动条都会造成浏览器的repaint,而且CPU的消耗也比较大,尤其是拖动滚动条的时候。

读取Layout属性

根据各种参考资料中的描述,在用Javascript读取DOM节点的Layout属性(offsetLeft、offsetTop、 offsetHeight、offsetWidth、scrollTop/Left/Width/Height、clientTop/Left /Width/Height、getComputedStyle()、currentStyle(in IE)) 的时候也会触发repaint,不过在以下的测试例子中并没有发现这一点。

  1. var n = $('colorNode');  
  2. var temp = document.documentElement.currentStyle;  
  3. temp = n.offsetTop;  
  4. temp = n.offsetLeft;  
  5. temp = n.offsetWidth;  
  6. temp = n.offsetHeight;  
  7. temp = n.scrollTop;  
  8. temp = n.scrollHeight;  
  9. alert(temp);  

image

 

三、浏览器优化

浏览器对于每一个渲染动作并不是立即执行,而是维护了一个渲染任务队列,浏览器会根据具体的需要分批集中执行其中的任务。除了浏览器自身维护的定期调度之外,脚本中的某些操作会导致浏览器立即执行渲染任务,例如读取元素的Layout属性。

  1. var bodystyle = document.body.style;  
  2. var computed;  
  3. if (document.body.currentStyle) {  
  4.   computed = document.body.currentStyle;  
  5. else {  
  6.   computed = document.defaultView.getComputedStyle(document.body, '');  
  7. }  
  8.   
  9. //每次都读取  
  10.   
  11. bodystyle.color = 'red';  
  12. bodystyle.padding = '1px';  
  13. tmp = computed.backgroundColor;  
  14. bodystyle.color = 'white';  
  15. bodystyle.padding = '2px';  
  16. tmp = computed.backgroundImage;  
  17. bodystyle.color = 'green';  
  18. bodystyle.padding = '3px';  
  19. tmp = computed.backgroundAttachment;  
  20.   
  21. //最后再读取  
  22.   
  23. bodystyle.color = 'yellow';  
  24. bodystyle.padding = '4px';  
  25. bodystyle.color = 'pink';  
  26. bodystyle.padding = '5px';  
  27. bodystyle.color = 'blue';  
  28. bodystyle.padding = '6px';  
  29. tmp = computed.backgroundColor;  
  30. tmp = computed.backgroundImage;  
  31. tmp = computed.backgroundAttachment;  

每次读取的渲染图:

image

最后读取的渲染图:

image

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

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

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

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

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

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

用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';  

3. 缓存Layout属性值

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

  1. var width = el.offsetWidth;  
  2. 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.   
  11.         ~function(){  
  12.             tt.style.left = t.offsetLeft + 5 + 'px';  
  13.             tt.style.height = t.offsetHeight + 5 + 'px';  
  14.             setTimeout(arguments.callee,500);  
  15.         }();  
  16.     }  
  17. </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

 

分享到:
评论

相关推荐

    如何减少浏览器的reflow和repaint

    总的来说,理解`reflow`和`repaint`的原理,并通过优化DOM操作、样式修改、缓存属性和利用定位属性等方式,可以有效地减少浏览器的渲染负担,提高网页性能。在实际开发中,开发者应当养成良好的编程习惯,时刻关注...

    JavaScript中的Repaint和Reflow用法详解

    等这些忠告,以前我就大概知道使用通配符或者CSS选择器层次过多可能会降低性能,至于为什么不使用table标签我一直是迷迷糊糊,也就跟着那样做了,但我认识了Repain和 Reflow之后,原来这些还真不能用太多。...

    有关javascript的性能优化 (repaint和reflow)

    **如何避免或减少Repaint和Reflow:** 1. **离线操作**:先移除元素,完成修改后再放回,减少对页面的影响。 2. **隐藏元素**:通过设置`display: none`,修改后再恢复,避免实时计算布局。 3. **使用...

    sisterAn#blog#浏览器的重绘与回流(Repaint、Reflow)1

    1. 浏览器渲染机制 2. 重绘 3. 回流 4. 浏览器优化 5. 减少重绘与回流

    浏览器渲染过程及优化策略

    浏览器渲染优化策略包括减少 repaint 和 reflow、合理使用缓存、使用 CSS 动画、避免过多的 DOM 操作、使用 lazy loading 等。这些策略可以减少浏览器的渲染时间,提高浏览器的性能和用户体验。 在浏览器渲染过程中...

    渲染篇 5:最后一击——回流(Reflow)与重绘(Repaint)(1).md

    在前端性能优化的领域中,回流(Reflow)与重绘(Repaint)是非常关键的概念。它们是浏览器渲染过程中最常见、也最影响性能的两个步骤。为了深入理解这两个概念,我们首先需要了解浏览器的渲染流程。 在用户通过...

    QT update和repaint

    在探讨QT中的`update`与`repaint`方法之前,我们先来理解一下这两个方法的基本概念及其在QT...在编写代码时,还应注意合理安排`update`和`repaint`的调用时机,以及正确地重写`paintEvent`函数以实现所需的绘制逻辑。

    100% Non Repaint Forex Scalping Indicator_repaint_nonrepaint_Fo

    "100% Non Repaint Forex Scalping Indicator" 是一款专为外汇交易者设计的指标,旨在提供无重复绘制(non-repaint)的交易信号,适用于所有货币对和任何时间框架。这款指标的核心优势在于其信号的稳定性,它在生成...

    Hill no repaint+Arrows1_repaint_hill_

    【描述】"hill no repaint for mt4" 进一步强调了这个指标是专为MT4设计的,不重绘的山形图(Hill Chart)能够帮助交易者识别趋势的方向和强度。在MT4平台上,用户可以利用这个指标来观察市场的动态,尤其是价格波动...

    Graphics 与 repaint 方法

    "Graphics 与 repaint 方法" Graphics 与 repaint 方法是图形编程中两个非常重要的概念。Graphics 是一个抽象类,提供了基本的绘图方法,如画直线、曲线等,而 repaint 方法则是用于触发图形组件的重绘。 ...

    HTML解析原理.pdf

    reflow和repaint是浏览器渲染过程中的重要环节,频繁的reflow会显著降低页面性能。因此,优化页面渲染的关键在于减少不必要的reflow。例如,为图片预先设定宽度和高度可以避免图片加载后引起的布局变化。此外,尽量...

    浏览器渲染过程与性能优化1

    这些过程通常被称为重排(Reflow)和重绘(Repaint),过多的重排和重绘会导致性能下降,因此应尽量避免不必要的操作。 性能优化可以从多个角度进行。例如,利用CSS的`display: none`或`visibility: hidden`来隐藏...

    WEB前端工程师Web前端性能优化经验分享

    2. 正确理解Repaint和Reflow Repaint(重绘)是指元素外观变化但不影响布局时发生的情况,例如改变颜色或边框。Reflow(重排)则是布局或几何属性发生变化时,浏览器需要重新计算元素及关联元素的布局。频繁的Reflow...

    新版前端高频面试题笔记+课件+源码(HTML+CSS+JavaScript)

    本视频主打内容最全最新,包括大前端基础与高频面试题,打造一站式知识长龙 服务,适合有前端基础的同学学习...2.如何最小化重绘(repaint)和回流(reflow)?3.Javascript作用域链? 4.数据请求 5.跨域和同源策略6.面向对象

    前端浏览器的工作流程详解

    在布局计算完成后,浏览器会进行回流(reflow)和重绘(repaint)两个重要步骤。回流指的是浏览器为了确定元素的位置和尺寸而进行的计算过程,这通常是在初次加载页面或进行DOM操作时发生。重绘则是当元素样式改变但...

    HTML解析原理.docx

    浏览器的渲染过程涉及多个步骤,包括解析HTML、CSS、JavaScript以及处理图片等资源,其中关键环节是页面的渲染、重绘(repaint)和...在实际开发中,应尽可能减少reflow和repaint的次数,以优化页面加载和交互速度。

    在浏览器输入一个网址发生了什么-阿沐1

    - 解析过程中,CSS和HTML可以并行加载,但JS执行会阻塞HTML解析,防止页面布局频繁变化(repaint和reflow)。 - 浏览器根据渲染树进行布局计算,确定每个节点的位置和大小,然后绘制到屏幕上,最终展示给用户。 ...

Global site tag (gtag.js) - Google Analytics