高性能WEB开发页面的呈现、重绘和回流
页面渲染过程是在讨论页面的重绘和重排之前。我们需要了解一些关于页面呈现过程的知识,以及页面如何在浏览器上显示html和css。下面的流程图展示了浏览器页面渲染的处理流程。也许不同的浏览器会略有不同。但它们基本相似。1.浏览器将得到的html代码解析成一个Dom树,html中的每个标签都是Dom树中的一个节点,根节点就是常用的文档对象(html标签)。Dom树是我们用firebug或者IE Developer Toolbar等工具看到的html结构,里面包含了所有的html标签,包括display:none隐藏,以及用JS动态添加的元素等。2.浏览器将所有样式(主要包括css和浏览器样式设置)解析成样式结构,在解析的过程中,浏览器无法识别的样式将被移除。例如,IE将删除以-moz开头的样式,而firefox将删除以_)开头的样式。3.dom树和样式结构组合在一起,构建了一个渲染树),渲染树与dom树有些相似,但实际上有很大的不同。渲染树可以识别样式,并且渲染树中的每个节点都有自己的样式。此外,渲染树不包含隐藏节点(如display:none节点和head节点),因为这些节点不会用于渲染,也不会影响渲染,所以它们不会包含在渲染树中。请注意visibility:hidden的隐藏元素仍将包含在渲染树中,因为visibility:hidden会影响布局并占用空间。按照css2的标准,渲染树中的每个节点都称为box(box dimensions),Box的所有属性都是宽度、高度、边距、填充、左侧、顶部、边框等。4.一旦构建了渲染树,浏览器就可以根据渲染树绘制页面。回流和重绘1。当由于元素的大小、布局和隐藏的改变而需要重建渲染树的一部分(或全部)时。这叫回流(其实我觉得叫重新布局更简单明了)。每个页面至少需要回流一次,也就是第一次加载页面的时候。2.当渲染树中的某些元素需要更新其属性时,这些属性只影响元素的外观和样式,而不影响布局,例如背景色。这叫做重绘。注意:从上面可以看出,回流必然会导致重绘,而重绘不一定会导致回流。什么会导致重绘和回流?事实上,对渲染树中元素的任何操作都会导致回流或重绘,例如:1。添加和删除元素(回流和重绘);2.隐藏元素,display:none,visibility:hidden(仅重绘,不回流);3.移动元素,如改变顶部。Left(左边的动画方法(jquery是改变顶部,左边不一定会影响回流),或者将元素移动到另一个父元素。(重绘和回流)4。对风格的操作(不同的属性操作有不同的效果)5。另一个是用户操作,比如改变浏览器大小和浏览器字体大小等。(回流和重绘)。让我们看看下面的代码如何影响回流和重绘。复制代码如下: var s=document . body . style;s.padding=' 2px//重排和重绘s.border='1px纯红';//重排并再次重绘s.color=' blue//再次重绘s.backgroundColor=' # ccc//再次重绘s.fontSize=' 14px//再次重排和重绘//添加节点,重排和重绘document . body . appendchild(document . createtextnode(' ABC!')又来了。));请注意我又在上面用了多少。在这里,我们都知道回流的成本比绘制的成本高,回流的成本与渲染树需要重建多少节点有关。如果直接操作主体,比如在主体的前面插入一个元素,会导致整个渲染树回流,当然成本会更高,但是如果你的意思是在主体后面插入一个元素,不会影响前面元素的回流。智能浏览器可以从上一个示例代码中看到,几行简单的JS代码导致了大约6次回流和重绘。
而且,我们也知道回流焊的成本不小。如果每次JS操作都回去重画,浏览器可能会受不了。因此,许多浏览器会优化这些操作。浏览器会维护一个队列,将所有会导致回流和重绘的操作放入这个队列。当队列中的操作数量达到一定数量或一定时间间隔时,浏览器将为批处理刷新队列。这样,多次回流和重绘将变成一次回流和重绘。虽然有浏览器优化,但有时候我们写的一些代码可能会强制浏览器提前清空队列,所以浏览器优化可能不会起作用。当你向浏览器询问一些样式信息时,你会让浏览器刷新队列,比如:1。Offsettop,OffsetLeft,OffsetWidth,offset theight 2 . scroll top/left/width/height 3 . client top/left/width/height 4 . width,height5.getcomputedstyle(),或ie的currentStyle。当您请求上述某些属性时,浏览器需要一个刷新队列,以便为您提供最准确的值,因为队列中可能存在影响这些值的操作。如何减少回流,重绘减少回流和重绘就是减少渲染树的操作,减少对一些样式信息的请求,充分利用浏览器的优化策略。方法如下:1 .与其逐个更改元素的样式属性,不如直接更改类名,但类名是预定义的样式,不是动态的。如果想动态改变一些样式,可以使用cssText来改变,参见下面的代码://Bad writing varleft=1;var top=1;El . style . left=left ' px ';el.style.top=top ' px//更好地编写El . class name=' class name 1 ';//更好地编写El . style . CSS text=';left: ' left ' pxtop: ' top ' px';2.使要操作的元素‘离线’,处理后一起更新。这里所谓的“离线处理”是指元素不存在于渲染树中,例如:a)使用documentFragment或div等元素进行缓存操作。当这个主要用来添加元素的时候,大家应该都用过,就是先把所有要添加的元素添加到一个div中(这个div也是新添加的),然后追加这个div。b)首先显示:none隐藏元素,然后对元素执行所有操作,最后显示元素。对display:none元素的操作不会导致重排和重绘。因此,只要进行操作,就只有两次反射。3不要频繁访问会导致浏览器刷新队列的属性。如果您真的想访问它们,您应该首先将它们读入变量进行缓存,然后在以后使用它们时直接读取它们。请看下面的代码://不要这样写,大哥for(loop){ El . style . left=El . offsetleft 5 ' px ';El . style . top=El . offsettop 5 ' px ';}//这样写好:varleft=el.offsetlft,top=el.offsettop,s=el.stylefor(loop){ left=10;top=10s.left=left ' pxs . top=top“px”;} 4.考虑渲染树中有多少节点将受到您的操作的影响,以及它将如何受到影响。受影响越大,花费肯定越大。例如,现在许多人使用jquery的动画方法来移动元素以显示一些动画效果。考虑以下两种移动方法://block1是由position:absolute定位的元素,其移动将影响其父元素下的所有子元素。//因为在其运动过程中,所有子元素都需要判断block1的z-index是否在自己身上。//如果是自己的话,需要重画,不会有$ ('# block1 ')的回流。动画({ left :50 });//block2是一个相对定位的元素,它影响的元素与block1相同。但是,由于block2不是绝对定位的//,而且marginLeft属性发生了变化,这里的每一个变化不仅会影响重绘,//还会导致父元素及其底层元素回流$(“# block 2”)。动画({ margin lef 336050 });在测试结束时,使用了两个工具来测试上述理论。这两个工具是在我的文章《推荐的web性能测试工具》中推荐的,分别是dynaTrace(测试IE)和Speed Tracer(测试Chrome)。第一个测试代码不改变元素的规则、大小和位置。
只改变颜色,所以不存在回流,仅测试重绘,代码如下:正文脚本类型=' text/JavaScript ' vars=document。尸体。风格;varcomputedif(文档。尸体。当前样式){计算=文档。尸体。当前样式;} else { computed=document。默认视图。getcomputed style(文档。正文,' ');} function testone byone(){ s . color=' red ';tmp=computed . background colors . color=' white tmp=computed . background images . color='绿色;tmp=已计算。背景附件;}functiontestAll() {s.color='黄色;s.color='粉色;s . color=' blue tmp=computed . backgroundcolortmp=computed . backgroundimagetmp=computed。背景附件;}/script color testbr/buttononclick=' testone byone()'逐个测试/buttonbuttononclick='testAll()'全部测试/button/body testOneByOne函数改变3次颜色,其中每次改变后调用getComputedStyle,读取属性值(按我们上面的讨论,这里会引起队列的同花顺),测试所有同样是改变3次颜色,但是每次改变后并不马上调用getComputedStyle。我们先点击逐一测试按钮,然后点击全部测试,用dynaTrace监控如下
从上图可以看出,我们执行了两次button的click事件,每次单击之后都是一次呈现(页面重绘)。两次点击功能的执行时间约为0.25毫秒、0.26毫秒,但之后的渲染时间增加了一倍多。(这里可以看到,其实大部分时候,前端的性能瓶颈不在于JS的执行,而在于页面的呈现,这在使用JS实现富客户端时更加突出。).再看下图,这是第一次渲染的详细信息。可以看到里面有2行,分别是调度布局任务。这是我们之前讨论过的由浏览器优化的队列。你可以看到我们触发了两次同花顺。
看第二次渲染的细节,可以看到没有Scheduleing布局任务,所以渲染时间比较短。测试2:该测试类似于第一次测试的代码,但是为了测试回流,增加了对布局的更改。DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN ' ' http://www . w3 . org/TR/XHTML 1/DTD/XHTML 1-Transitional . DTD ' html xmlns=' http://www . w3 . org/1999/XHTML ' head/head/head dyscript type=' text/JavaScript的vars=document . body . style;varcomputedif(document . body . current style){ computed=document . body . current style;} else { computed=document . default view . getcomputed style(document . body,' ');} functiontestone byone(){ s . color=' red ';s.padding=' 1pxtmp=computed.backgroundColors.color=' whites.padding=' 2pxtmp=computed.backgroundImages.color='绿色';s.padding=' 3pxtmp=computed . background attachment;}functiontestAll() {s.color='黄色';s.padding=' 4pxs.color='粉色';s.padding=' 5pxs.color=' blues.padding=' 6pxtmp=computed.backgroundColortmp=computed.backgroundImagetmp=computed . background attachment;}/script color testbr/button onclick=' testone by one()' testone by one/button button=' testall()' testall/button/body由dynaTrace监控,如下所示:。
相信这个数字大家都能理解。可以看到,回流后的渲染时间只比上一次重绘,时间翻了三倍,展现了回流的高质量本质。当你看到它时,你应该注意到细节部分与前一个相比有一个calcalcalating流程布局。最后,使用Speed Tracer再次测试。其实结果都是一样的,只是为了让大家知道接下来的两个测试工具:Test 1: 。
在图形上,第一次单击执行2毫秒(其中50%用于样式重新计算),第二次单击执行1毫秒,第一次单击之后是两次样式重新计算,而第二次单击没有样式重新计算。但是这次测试发现油漆的重绘时间是一样的,都在3ms,这可能就是chrome比IE好的原因。测试2:
从图中可以发现,第二次测试结果在时间上与第一次测试结果完全相同。这可能是因为操作太少,chrome相对强大,所以明显的测试结果无法出来。但是,请注意,图中有一个紫色部分,这是布局部分。这就是我们所说的回流。【声明】请注明来源于:http://www.blogjava.net/BearRui/.禁止商业使用!
版权声明:高性能WEB开发页面的呈现、重绘和回流是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。