狠狠撸

狠狠撸Share a Scribd company logo
浏览器的   回流 与 重绘


                              分享 by 张盛志




                 Contact Me

                 QQ: 185766516
                 E-mail: shengzhizhang@gmail.com
浏览器的线程

浏览器内核允许多线程异步执行,这些线程相互进行通信、相互配合以实现同步。常驻线程有以下3个:


GUI渲染线程:

该线程主要负责渲染页面中的HTML元素,当界面需要重绘或由于某种操作引发回流时,该线程就会执行。


JavaScript 引擎线程:

JavaScript线程是基于事件驱动单线程执行的。这意味着同一时间只有一句脚本在执行,而所有的异步事件都

被强制排队等待执行。


事件触发线程:

当一个事件被触发时该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理。




                                          Contact Me
                         1   of   11      QQ: 185766516
                                          E-mail: shengzhizhang@gmail.com
线程之间的关系

GUI线程与JavaScript引擎线程是互斥的。也就是说,在JavaScript引擎运行脚本期间,GUI线程一直处于挂起

状态。

所以,在脚本中执行对界面进行更新操作,如添加结点,删除结点或改变结点的外观等更新并不会立即体现出

来。GUI的更新会被保存在一个队列中,待JavaScript引擎空闲时立即执行。

JavaScript引擎线程一直在等待加入事件队列中的事件,一有事件加入,立即执行。




事件触发线程(捕获                                  GUI渲染线程(冻结)
  各种事件)




            Interval   Interval   Timer
                                               Mouse Click   JavaScript      JavaScript
                                                Callback      Callback       引擎线程

                                                              正在运行



                                                                          Contact Me
                                    2     of   11                         QQ: 185766516
                                                                          E-mail: shengzhizhang@gmail.com
浏览器的渲染过程

1. 解析HTML代码并生成一个 DOM 树。

2. 解析CSS样式,顺序为:浏览器默认样式->自定义样式->页面内的样式

3. 生成一个渲染树(不包括不可见的节点)。

4. 当渲染树生成之后,浏览器就会在屏幕上“画”出所有渲染树中的节点。




     HTML代码           DOM树


                                           渲染树                Paint!


     CSS样式           样式结构




                                                 Contact Me
                             3   of   11         QQ: 185766516
                                                 E-mail: shengzhizhang@gmail.com
例子:

请先看一个简单的页面:                                                                  <img src=/RandyJin/reflow-repaint/"img/d2_180x250.jpg" alt="D平方" />

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"               <div id="mod1">Mod1</div>

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">                   <div id="mod2">Mod2</div>

<html xmlns="http://www.w3.org/1999/xhtml">                                  <script src="js/util.js" type="text/javascript" ></script>

<head>                                                                       <script type="text/javascript">

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />          var el = id('mod1');

<title>A simple page</title>                                                   hide(el);

<link rel="stylesheet" href="css/main.css" type="text/css"                   </script>

media="screen" />                                                       </body>

</head>                                                                 </html>




<body>




                                                                                                                     Contact Me
                                                                  4     of     11                                    QQ: 185766516
                                                                                                                     E-mail: shengzhizhang@gmail.com
例子:

向服务器发出HTML文   发现一个<link>标签引                                    CSS文件到手,开始渲
                                            发出CSS文件的请求
   件的请求        用外部CSS文件                                                 染页面




图片影响了后面元素的
              不等图片下载完,继续                向服务器发出图片文件              发现一个<img>标签引
排布,回过头来重新渲
               渲染后面的代码                         请求                   用了一张图片
  染这部分代码




发现了一段JS代码,赶   某个元素被隐藏,不得
                                              渲染完毕
  快运行它!       不重新渲染这部分代码




                                                         Contact Me
                              5   of   11                QQ: 185766516
                                                         E-mail: shengzhizhang@gmail.com
浏览器的Reflow 和Repaint

页面打开缓慢的原因是多方面的:服务器响应、网络质量、JS阻塞等等。

其中一个跟浏览器有关的原因,那就是浏览器需要花时间、花精力去渲染。当它发现某个部分发生了变化影响

了布局,需要倒回去重新渲染,我们就称这个回退的过程叫Reflow。

只要某些行为引起了页面上某些元素的占位面积、定位方式、边距等属性的变化,都会引起这些元素内部、周

围甚至整个页面的重新渲染。

Repaint比较好理解,其实就是浏览器根据重新计算的各个属性值对页面的部分元素进行重新绘制。

如果只是改变某个元素的背景色、文字颜色、边框颜色等等不影响它周围或内部布局的属性,将只会引起浏览

器Repaint。Repaint的速度明显快于Reflow(在IE下需要换一下说法,Reflow要比Repaint更缓慢-0-)。




                                                    Contact Me
                               6   of   11          QQ: 185766516
                                                    E-mail: shengzhizhang@gmail.com
引起Reflow 和Repaint 的因素

? Resize浏览器窗口、滚动页面

? 字体的改变(大小,颜色,行高等)

? 添加/删除一个样式表

? 应用新的样式或者修改任何影响元素外观的属性

? 伪类(例如:hover)

? DOM元素的添加、修改(内容)、删除

? 读取元素的某些属性(offsetLeft、offsetTop、offsetHeight、offsetWidth、

 scrollTop/Left/Width/Height、clientTop/Left/Width/Height、 getComputedStyle()、currentStyle(in

 IE))




                                                                         Contact Me
                                           7   of   11                   QQ: 185766516
                                                                         E-mail: shengzhizhang@gmail.com
如何尽量减少Reflow 和Repaint?

? 尽可能限制reflow的影响范围。

? 如果通过设置style属性改变结点样式,每设置一次都会导致一次reflow。所以最好通过设置class的方式。

? 实现元素的动画,它的position属性应当设为fixed或absolute,这样不会影响其它元素的布局。

? 在效果和性能上取得平衡。

? 不要用tables进行布局。Table的子元素只要有一个触发了reflow,会导致整个表格的其他元素都发生reflow,而且它产

 生reflow的时间,是其他block元素的reflow的3倍。在适合使用table的场合,定义table-layout的属性值为auto或fixed,

 让其一行一行输出。

? 避免在CSS中使用表达式。如果CSS里有expression,每个expression都会导致CSS重新计算一遍。很多情况下都会触

 发reflow。

? 页面上尺寸可以确定的元素,例如图片,文本框等等,最好为其定义高度和宽度。




                                                            Contact Me
                                   8   of   11              QQ: 185766516
                                                            E-mail: shengzhizhang@gmail.com
如何尽量减少Reflow 和Repaint?

? 避免在document上直接进行频繁的DOM操作,如果确实需要可以采用off-document的方式进行。

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

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

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

? 集中修改样式。

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

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

? 缓存Layout属性值。这样可以避免每次读取属性时造成浏览器的渲染。




                                                      Contact Me
                                  9   of   11         QQ: 185766516
                                                      E-mail: shengzhizhang@gmail.com
小结

本次交流会旨在简单阐述了浏览器的工作原理、渲染过程、回流和重绘产生的原因以及如何减少过多的回流和重绘,并且

通过几个例子较为“深入”地认识了浏览器的回流和重绘。

网页的优化是一个繁琐而又困难的过程,其间存在太多不可预料的因素,而针对浏览器所作的优化只是冰山一角,还有许

许多多方面需要我们深入去探讨和挖掘,希望本文对您有所帮助。

因时间仓促,难免出现纰漏,欢迎大家多提建议。




                                         Contact Me
                         10 of   11      QQ: 185766516
                                         E-mail: shengzhizhang@gmail.com
参考文献

Note on HTML Reflow

链接:http://www.mozilla.org/newlayout/doc/reflow.html

Reflows & Repaints: CSS Performance making your JavaScript slow?

链接:http://www.stubbornella.org/content/2009/03/27/reflows-repaints-css-performance-making-your-javascript-slow/

Efficient JavaScript - Dev.Opera

链接:http://dev.opera.com/articles/view/efficient-javascript/?page=3#reflow

Understanding Internet Explorer Rendering Behaviour

链接:http://blog.dynatrace.com/2009/12/12/understanding-internet-explorer-rendering-behaviour/




                                                                                        Contact Me
                                                     11 of   11                         QQ: 185766516
                                                                                        E-mail: shengzhizhang@gmail.com
THANK YOU!




             Contact Me

             QQ: 185766516
             E-mail: shengzhizhang@gmail.com

More Related Content

reflow & repaint