美文网首页
重绘和重排性能优化

重绘和重排性能优化

作者: 小宇cool | 来源:发表于2020-06-07 18:29 被阅读0次
  1. 重绘和重排

1.1 DOM树和渲染树

浏览器下载完页面中的所有组件、HTML标记,javascript,css图片、之后会解析并生成两个内部的数据结构

DOM树:

​ 表示页面结构

渲染树:

​ 表示DOM节点如何显示

DOM树中每一个需要显示的节点在渲染树中至少存在一个对应的节点,(隐藏的DOM元素没有对应的节点).渲染树中的节点被称为.一旦DOM树和渲染树构建起来,浏览器就会显示(绘制"paint") 页面元素.

1.2 什么是重绘和重排

当DOM的变化改变了元素的几何属性,例如宽和高,或者改变了边框高度,给段落增加文本,等等等.都会导致浏览器需要重新计算元素的几何属性,同样其他的元素的几何属性个位置也会因此受到影响,浏览器会使渲染树受到影响的部分失效, 并重新构建渲染树, 这个过程称为 "重排". 完成重排后, 浏览器会重新绘制受影响的部分到屏幕中,该过程称为"重绘".

并不是所有的DOM变化都会影响几何属性,例如改变一个元素的背景色并不会改变他的宽和高, 在这种情况下,只会发生一次重绘,因为页面的布局并没有改变.

重绘和重排都是代价昂贵的操作,它们会导致web应用程序的UI反应迟钝, 所以尽可能得减少这类操作的发生.

1.3 重排何时发生

  • 添加或删除可见的元素
  • 元素的位置发生了改变
  • 元素的尺寸发生了改变, 包括外边距, 内边距, 边框宽度, 高度等属性被改变
  • 内容改变, 例如: 文本改变或者图片被另一个不同尺寸的图片替代
  • 页面渲染器初始化
  • 浏览器可视区域尺寸改变

根据改变的范围和程度, 渲染树或大或小对应的部分都需要重新计算然后渲染到页面上, 有些改变会触发整个页面的重排,

例如当滚动条出现时.

1.4 最小化重绘和重排

重绘和重排对性能的消耗十分昂贵,因此一个好的提高程序响应速度的方法减少减少此类操作的发生.

为了减少发生次数,应该合并多次对DOM和样式的修改,然后一次性处理掉.

通过DOM改变元素样式:

let el = document.getElementById("div")
el.style.width = "434px";
el.style.padding = "4px";
el.style.borderLeft = "6px";

示例中三个样式属性被改变, 每一次都影响了元素的几何结构.最糟糕的情况下,会导致浏览器触发三次重排.大部分现代浏览器为此做了优化,只会触发一次重排.但是在旧版本浏览器中仍然效率低下.

一个能够得到同样效果且效率更高的方式是: 合并所有的改变然后一次性处理,这样只会改变DOM一次.使用cssText属性可以实现.

let el = document.getElementById("div")
el.style.cssText = 'width:12px; height:46px; padding:4px'

例子上的代码修改了cssText属性并覆盖了已存在的样式信息, 因此如果向保留现有样式,可以把他附加到cssText字符串后面.

el.style.cssText += 'padding-left:5px'

​ 另外一种一次性改变元素元素的方法是修改css的class类名 ,而不是修改内联样式改变css的Clss名称的方法更清晰,更易于维护.

let el = document.getElementById("div")
el.className = 'style';
el.classList.add("active")

1.5 批量修改DOM

当年需要对DOM元素进行一系列操作时,可以通过以下步骤来减少重绘和重排的次数:

  1. 使元素脱离文档流
  2. 对其应用进行多重改变
  3. 将文档带回文档流

该过程里会触发两次重排---> 第一步和第三步. 如果你忽略第这两个步骤, 那么在第二步所产生的任何修改都会触发一次重排

有三种基本方法可以使DOM脱离文档:

  • 隐藏元素, 应用修改, 重新显示
  • 使用文档碎片 在DOM树之外构建一个子树,再把它拷贝会文档
  • 将原始元素拷贝到一个脱离文档的节点, 修改副本,完成之后在替换原始元素

假设我们有一个普通的列表文本,我们要更新其中的文本内容

   <ul id="myList"> 
        <li> text1 </li>
        <li> text2 </li>
    </ul>                    

假设数据已经定义到一个数组对象中,要插入这些列表. 这些数据定义如下

let data = [ {text:"text3"}, {text:"text4"}]

下面是是一个用来更新指定节点数据通用函数

function updatePageData(appendEle,data){
    let li;
    for(let i = 0,max = data.length; i < max;i++){
        li = document.createElement("li");
        li.textContent = data[i].text;
        appendEle.append(li)
    }
}

我们通过会使用下面这种正常的方法调用这个函数

let myList = document.getElementById("myList");
updatePageData(myList,dataArr)

然而使用上面这种方法,data数据中的每一次数据被附加到当前DOM树,都会导致一次重排.正如上文所讲到的,一种减少

重排的方法是通过改变display属性, 临时从文档中移除ul元素, 然后在恢复他

let myList = document.getElementById("myList");
myList.style.display = 'none'
updatePageData(myList,dataArr);
myList.style.display = 'block';

另一种改变重排的次数:在文档之外创建一个文档碎片,然后把它附加到原始列表中

let fragment = document.createDocumentFragment();
updatePageData(fragment,dataArr);
myList.append(fragment); 

第三种解决方案是为需要修改的节点创建一个备份. 然后对副本进行操作, 一旦操作完成,就有新的节点替代旧的节点.

let myList = document.getElementById("myList");
let clone = myList.cloneNode(true);
updatePageData(clone,dataArr);
myList.parentNode.replaceChild(clone, myList)

我们推荐使用第二个方案( 文档碎片) 因为它所产生的DOM遍历和重排次数最少.

相关文章

  • 前端收藏文章

    优化CSS重排重绘与浏览器性能

  • 重绘和重排性能优化

    重绘和重排 1.1 DOM树和渲染树 浏览器下载完页面中的所有组件、HTML标记,javascript,css图片...

  • 重绘和重排及其性能优化

    了解了浏览器渲染原理之后,我们知道了浏览器听过渲染树计算布局后,就开始绘制页面元素,但是渲染树并不是一成不变的,在...

  • 浏览器的重绘和重排

    重绘和重排 重排是因为元素的几何属性改变,导致渲染树中的节点发生改变,从而影响到其它节点发生重绘。重排对性能影响极...

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

    前言,最近利用碎片时间拜读了一下尼古拉斯的另一巨作《高性能JavaScript》,今天写的文章从“老生常谈”的页面...

  • 逐行分析snabbdom.js源码

    VirtualDOM 是针对 DOM 重排重绘性能瓶颈作出的重要优化方案,其最具价值的核心功能是如何识别并保存新旧...

  • web性能优化 - 重排与重绘

    重排与重绘 重排 [重构/回流/reflow]:当DOM变化影响了节点的几何属性,浏览器需要重新计算节点的几何属性...

  • React + Reflux 渲染性能优化原理

    React对重排和重绘的提高雅虎性能优化比较重要的点,老司机自行忽略。如下图,HTML被浏览器解析为DOM树,CS...

  • 前端性能优化之重排和重绘(转)

    原文 一.重排 & 重绘 有经验的大佬对这个概念一定不会陌生,“浏览器输入URL发生了什么”。估计大家已经烂熟于心...

  • react 组件性能优化

    影响网页性能最大的因素是浏览器的重绘(reflow)和 重排 (repaint)。react 背后的 virtua...

网友评论

      本文标题:重绘和重排性能优化

      本文链接:https://www.haomeiwen.com/subject/edthtktx.html