一、什么是重排和重绘

要说清重排(reflow)和重绘(repaint),首先要了解排列和绘制,浏览器渲染页面时,在获取完html、css资源之后,会大抵通过以下步骤。
(1) html生成html树
(2) css造成css规定
(3) 两者造成一个渲染树
(4) 去文档当中找寻各自的布局地位----- 排列
(5) 将内容填充到文档上 ----- 绘制
【排列】就是计算地位调整布局的过程,而【绘制】就是把它画下来的过程。【重排】也就是除了最开始排列的布局,后续通过一些操作而使得dom元素从新找寻地位的过程,【重绘】就是从新绘制内容的过程。

二、什么状况会引发重排和重绘

1、先来说重排,重排和地位的挪动布局的变动无关,次要有以下几种状况会引发重排
(1) 浏览器的窗口发生变化,每放大、放大一次浏览器的窗口,该页面的所有元素都要进行重排重绘
(2) 减少、删除、挪动dom元素,更改dom元素的宽高内外边距、内容,批改dom元素的款式
(3) 进行dom元素宽低等属性的查问,因为每查问一次,浏览器都会对所有的元素进行从新计算,以确保计算的值是正确的

2、再来说重绘,重绘次要是元素的外观发生变化,不会从新布局,有以下状况会引发重绘
元素的背景(background)、文字色彩(color)、边框款式(outline)发生变化

3、重排和重绘的关系
重绘不肯定须要重排,因为可能只是元素批改文字色彩,不须要从新布局,重排大多数状况都须要重绘,因为重新排列元素之后要绘制到屏幕上。

以下显示重排和重绘的耗时,方块两秒之后右移了100px

三、为什么要优化

因为重排和重绘不只是对单个的dom元素进行操作,而是对整个【图层】进行操作,须要破费工夫,如果频率高,十分的影响性能。

那什么是图层?如下图所示

因为每一次的重排重绘都是操作整个图层,那么咱们能够将须要频繁操作的dom元素另外建设一个图层,这样能够尽可能少的触发重排重绘。

那么什么状况能够开启图层?
针对频繁操作的行为,chrome浏览器主动开启了图层,次要有以下几种状况
1、css 3D变动的图形 ---- transform: translateX(0)
2、html5中的<video>标签
3、canvas绘图中的节点
4、css 动画的节点 --- keyframes animation
5、领有css减速属性 --- will-change: transform

除此之外,还能够应用以下形式进行优化
1、对元素进行挪动时,应用transform代替对元素top、left、right的操作,因为css3的整个操作是对图层的组合来实现的,所以不会引发重绘重排。

#node{  // position: relative;   transform: translateX(0);  width: 100px;  height: 100px;  background: pink;}var node = document.querySelector("#node");setTimeout(function(){    //   node.style.left="100px";   node.style.transform="translateX(100px)";},2000);

同样是对一个元素两秒后挪动100px,能够看到比照下图比照

2、将屡次对款式的操作合并成一次
不要一次一次的批改款式,而是事后定义好class,间接批改DOM的className,这样只会引发一次重排重绘
3、将dom离线后批改
如果要对dom元素进行屡次操作,首先将dom设置为不可见,而后再对dom操作,操作实现后再将dom元素设置为可见,这样只会有两次重排重绘
4、利用文档碎片 documentFragment
documentFragment 不是实在 dom树的一部分,它的变动不会触发dom树的从新渲染,且不会导致性能等问题,将创立的新元素全副增加到documentFragment上,最初让documentFragment一起插入到dom元素中

const list = ['哈尔的挪动城堡', '千与千寻的神隐', '起风了']const ul = document.getElementsByTagName("ul")[0]let fragment = document.createDocumentFragment()for(let i in list){    fragment.appendChild(list[i])}ul.appendChild(fragment)