您现在的位置是:首页 > 文章详情

前端性能优化之重排和重绘

日期:2018-11-13点击:325

前言,最近利用碎片时间拜读了一下尼古拉斯的另一巨作《高性能JavaScript》,今天写的文章从“老生常谈”的页面重绘和重排入手,去探究这两个概念在页面性能提升上的作用。

一.重排 & 重绘

有经验的大佬对这个概念一定不会陌生,“浏览器输入URL发生了什么”。估计大家已经烂熟于心了,从计算机网络到JS引擎,一路飞奔到浏览器渲染引擎。 经验越多就能理解的越深。感兴趣的同学可以看一下这篇文章,深度和广度俱佳 从输入 URL 到页面加载的过程?如何由一道题完善自己的前端知识体系!

切回正题,我们继续探讨何为重排。浏览器下载完页面所有的资源后,就要开始构建DOM树,于此同时还会构建渲染树(Render Tree)。(其实在构建渲染树之前,和DOM树同期会构建Style Tree。DOM树与Style Tree合并为渲染树)

  • DOM树 
    表示页面的结构
  • 渲染树 
    表示页面的节点如何显示

一旦渲染树构建完成,就要开始绘制(paint)页面元素了。当DOM的变化引发了元素几何属性的变化,比如改变元素的宽高,元素的位置,导致浏览器不得不重新计算元素的几何属性,并重新构建渲染树,这个过程称为“重排”。完成重排后,要将重新构建的渲染树渲染到屏幕上,这个过程就是“重绘”。简单的说,重排负责元素的几何属性更新,重绘负责元素的样式更新。而且,重排必然带来重绘,但是重绘未必带来重排。比如,改变某个元素的背景,这个就不涉及元素的几何属性,所以只发生重排。

二. 重排触发机制

上面已经提到了,重排发生的根本原理就是元素的几何属性发生了改变,那么我们就从能够改变元素几何属性的角度入手

  • 添加或删除可见的DOM元素
  • 元素位置改变
  • 元素本身的尺寸发生改变
  • 内容改变
  • 页面渲染器初始化
  • 浏览器窗口大小发生改变

三. 如何进行性能优化

重绘和重排的开销是非常昂贵的,如果我们不停的在改变页面的布局,就会造成浏览器耗费大量的开销在进行页面的计算,这样的话,我们页面在用户使用起来,就会出现明显的卡顿。现在的浏览器其实已经对重排进行了优化,比如如下代码:

var div = document.querySelector('.div'); div.style.width = '200px'; div.style.background = 'red'; div.style.height = '300px';

比较久远的浏览器,这段代码会触发页面2次重排,在分别设置宽高的时候,触发2次,当代的浏览器对此进行了优化,这种思路类似于现在流行的MVVM框架使用的虚拟DOM,对改变的DOM节点进行依赖收集,确认没有改变的节点,就进行一次更新。但是浏览器针对重排的优化虽然思路和虚拟DOM接近,但是还是有本质的区别。大多数浏览器通过队列化修改并批量执行来优化重排过程。也就是说上面那段代码其实在现在的浏览器优化下,只构成一次重排。

但是还是有一些特殊的元素几何属性会造成这种优化失效。比如:

  • offsetTop, offsetLeft,...
  • scrollTop, scrollLeft, ...
  • clientTop, clientLeft, ...
  • getComputedStyle() (currentStyle in IE)

为什么造成优化失效呢?仔细看这些属性,都是需要实时回馈给用户的几何属性或者是布局属性,当然不能再依靠浏览器的优化,因此浏览器不得不立即执行渲染队列中的“待处理变化”,并随之触发重排返回正确的值。

接下来深入的介绍几种性能优化的小TIPS

3.1 最小化重绘和重排

既然重排&重绘是会影响页面的性能,尤其是糟糕的JS代码更会将重排带来的性能问题放大。既然如此,我们首先想到的就是减少重排重绘。

3.1.1. 改变样式

考虑下面这个例子:

// javascript var el = document.querySelector('.el'); el.style.borderLeft = '1px'; el.style.borderRight = '2px'; el.style.padding = '5px';

这个例子其实和上面那个例子是一回事儿,在最糟糕的情况下,会触发浏览器三次重排。然鹅更高效的方式就是合并所有的改变一次处理。这样就只会修改DOM节点一次,比如改为使用cssText属性实现:

var el = document.querySelector('.el'); el.style.cssText = 'border-left: 1px; border-right: 2px; padding: 5px';

沿着这个思路,聪明的老铁一定就说了,你直接改个类名不也妥妥的。没错,还有一种减少重排的方法就是切换类名,而不是使用内联样式的cssText方法。使用切换类名就变成了这样:

// css .active { padding: 5px; border-left: 1px; border-right: 2px; } // javascript var el = document.querySelector('.el'); el.className = 'active';

3.1.2 批量修改DOM

3.1.3 缓存布局信息

3.2让元素脱离动画流

原文链接:https://my.oschina.net/u/3999152/blog/2875484
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章