浏览器的回流和重绘

浏览器的渲染过程

clipboard.png

从上面这个图上,我们可以看到,浏览器渲染过程如下

  1. 解析HTML生成DOM树,解析CSS生成CSSOM
  2. DOM树和CSSOM树结合生成渲染树renderTree
  3. Layout(回流): 根据生成的渲染树,进行回流(Layout),得到节点的几何信息(位置,大小)
  4. Painting(重绘): 根据渲染树以及回流得到的几何信息,得到节点的绝对像素
  5. Display:将像素发送给GPU,展示在页面上。

生成渲染树(RenderTree)

clipboard.png

为了构建渲染树,浏览器主要完成了以下工作

  1. DOM树的根节点开始遍历每个可见节点。
  2. 对于每个可见的节点,找到CSSOM树中对应的规则,并应用它们。
  3. 根据每个可见节点以及其对应的样式,组合生成渲染树。

第一步中,既然说到了要遍历可见的节点,那么我们得先知道,什么节点是不可见的。不可见的节点包括:

  1. 一些不会渲染输出的节点,比如script、meta、link等。
  2. 一些通过css进行隐藏的节点。比如display:none。注意,利用visibilityopacity隐藏的节点,还是会显示在渲染树上的。只有display:none的节点才不会显示在渲染树上。

回流(Layout)

前面我们通过构造渲染树,我们将可见DOM节点以及它对应的样式结合起来,可是我们还需要计算它们在设备视口(viewport)内的确切位置和大小,这个计算的阶段就是回流。
为了弄清每个对象在网站上的确切大小和位置,浏览器从渲染树的根节点开始遍历,而在回流这个阶段,我们就需要根据视口具体的宽度,将其转为实际的像素值

重绘(Painting)

通过回流(Layout)阶段,我们知道了所有的可见节点的样式和具体的几何信息(位置、大小),那么我们就可以将渲染树的每个节点都转换为屏幕上的实际像素,这个阶段就叫做重绘节点。

何时发生回流重绘

回流阶段是计算节点的几何信息和位置,那么当页面布局或者几何信息发生改变时,就需要回流。

  1. 添加或者删除可见的DOM元素
  2. 元素的位置、尺寸发生变化
  3. 页面开始渲染的时候(这肯定避免不了)
  4. 浏览器的视口尺寸大小发生改变(因为回流是根据浏览器视口的大小来计算元素的位置和尺寸大小)

注意:回流一定会触发重绘,而重绘(非几何信息的样式发生改变)不一定会回流, reflow回流的成本开销要高于repaint重绘,一个节点的回流往往回导致子节点以及同级节点的回流;

根据改变的范围和程度,渲染树中或大或小的部分需要重新计算,有些改变会触发整个页面的重排,比如,滚动条出现的时候或者修改了根节点。

基于回流(Layout)、重绘(Painting)的优化方法

避免扰乱现代浏览器的优化机制

在现代浏览器的中,由于每次回流、重绘的时候,都需要额外的计算消耗,因此会通过队列化修改,并批量执行来优化这一过程。浏览器会将修改操作放入队列里面,直到过了一段时间或者达到一个阈值,才清空队列。

但是当你获取布局信息时,会强制刷新队列,例如:

offsetTop、offsetLeft、offsetWidth、offsetHeight

scrollTop、scrollLeft、scrollWidth、scrollHeight

clientTop、clientLeft、clientWidth、clientHeight

getComputedStyle()

getBoundingClientRect()

上面这些方法,都需要获取最新的布局信息,所以浏览器会强制刷新队列并执行回流、重绘,来获取最新的信息。
因此我们在修改样式的时候,应该尽量避免使用上面的属性、方法,如果非要使用,可以先缓存起来然后一起获取。

CSS的修改方式

考虑以下代码

const el = document.getElementById('el')
el.style.padding = 'xxx'
el.style.margin = 'xxx'
el.style.border = 'xxx'

这里元素的几何信息有三次被修改了,但是现代浏览器会将起缓存起来,但是如果这期间有通过前面列出来的属性、方法访问位置信息的话就会触发三次回流、重绘。所以还是建议通过cssText或者class的方法一次性修改。

el.style.cssText += 'border-left: 1px; border-right: 2px; padding: 5px;';
// 或者
el.className += 'xxx';
批量修改DOM

当我们需要对DOM进行一系列修改的时候,可以通过以下几种方式减少回流重绘次数:

  • 隐藏元素,应用修改,重新显示
function appendDataToElement (appendToElement, data) { 
    let li;
    for ( let i = 0; i < data.length; i++) {
     li = document.createElement('li');
     li.textContent = 'text';
     appendToElement.appendChild(li);    
    }
}

const ul = document.getElementById('list');
ul.style.display = 'none'; // 首先脱离文档流
appendDataToElement(ul, data);
ul.style.display = 'block'; // 操作完以后再可见
  • 使用文档片段(document fragment)在当前DOM之外构建一个子树,再把它拷贝回文档。
const ul = document.getElementById('list');
const fragment = document.createDocumentFragment()
appendDataToElement(fragment , data);
ul.appendChild(fragment )
独立图层

一个图层的回流和重绘只会在该图层当中进行,不会影响其他图层,所以有必要的时候,可以将某些元素放到单独的图层。

例如对于复杂动画效果,由于会经常的引起回流重绘,因此,我们可以使用绝对定位,让它脱离文档流, 成为一个单独的图层。否则会引起父元素以及后续元素频繁的回流。但是因该尽量少量使用图层,因为图层的合成是特别消耗性能,一个页面当中不能有过多的图层, 在使用了图层之后需要进行前后对比

会自动建立图层的情况:

  • 3d或者透视变换、过渡css属性
  • 使用<video>节点
  • <canvas>
  • flash
  • 多透明度做 css动画

其他优化

  • 用translate替代top改变: top会触发回流,而前者不会
  • 用opacity替代visibility: 前者回流重绘都不会触发(前提是它单独在一个图层),后者两个都会触发
  • 不要使用table布局,table的可能很小的一个改动会造成回流,很影响性能,应该尽量使用 div。
  • 动画实现的速度选择:
  • 对于动画新建图层
  • 启用GPU硬件加速: 使用transform:translateZ(0) 、transform:translate3d(0,0,0)来开启GPU硬件加速

CSSJS 是这样阻塞 DOM 解析和渲染的

通过<script><link>引入外部资源,当解析到该标签的时候,会进行下载。

  1. CSS脚本的加载不会阻塞 DOM 解析过程,但是会阻塞渲染过程(painting)
  2. JS脚本的加载与执行会阻塞 DOM 解析过程, 但是不会阻塞后续资源的加载
  3. JS脚本的加载中,如果你确定没必要阻塞 DOM 解析的话,不妨按需要加上 defer 或者 async 属性,此时脚本下载的过程中是不会阻塞 DOM 解析的。
  4. 浏览器遇到 <script>且没有 deferasync 属性的标签时,为了为<script>标签内部的js提供最新的信息,会触发页面的回流、重绘过程。
  5. 如果前面 CSS 资源尚未加载完毕时,浏览器会等待它加载完毕之后再执行脚本。即 css 不阻塞 js 的加载,但阻塞它的执行。

所以<script>最好放底部(防止阻塞DOM解析)。<link>最好放头部(为渲染过程提供样式)。如果头部同时有<script><link>的情况下,最好将<script>放在<link>上面(为了防止CSS脚本加载时间过长,使js等待时间也很长)dd

内容概要:本文详细探讨了基于MATLAB/SIMULINK的多载波无线通信系统仿真及性能分析,点研究了以OFDM为代表的多载波技术。文章首先介绍了OFDM的基本原理系统组成,随后通过仿真平台分析了不同调制方式的抗干扰性能、信道估计算法对系统性能的影响以及同步技术的实现与分析。文中提供了详细的MATLAB代码实现,涵盖OFDM系统的基本仿真、信道估计算法比较、同步算法实现不同调制方式的性能比较。此外,还讨论了信道特征、OFDM关键技术、信道估计、同步技术系统级仿真架构,并提出了未来的改进方向,如深度学习增强、混合波形设计硬件加速方案。; 适合人群:具备无线通信基础知识,尤其是对OFDM技术有一定了解的研究人员技术人员;从事无线通信系统设计与开发的工程师;高校通信工程专业的高年级本科生研究生。; 使用场景及目标:①理解OFDM系统的工作原理及其在多径信道环境下的性能表现;②掌握MATLAB/SIMULINK在无线通信系统仿真中的应用;③评估不同调制方式、信道估计算法同步算法的优劣;④为实际OFDM系统的设计优化提供理论依据技术支持。; 其他说明:本文不仅提供了详细的理论分析,还附带了大量的MATLAB代码示例,便于读者动手实践。建议读者在学习过程中结合代码进行调试实验,以加深对OFDM技术的理解。此外,文中还涉及了一些最新的研究方向技术趋势,如AI增强毫米波通信,为读者提供了更广阔的视野。
### 浏览器渲染中的回流 #### 回流(Reflow) 回流是指当 DOM 的结构或元素的几何属性(如大小、位置等)发生变化时,浏览器需要新计算这些元素的位置尺寸,并更新整个页面布局的过程。这一过程通常涉及多个节点的新计算以及可能引发后续子树的调整[^1]。 例如,如果动态改变了某个元素的高度或者宽度,或者是隐藏了一个可见的元素,则会触发回流操作。每次回流都会带来一定的性能开销,尤其是复杂的布局场景下更为显著[^5]。 #### (Repaint) 相比之下,指的是由于某些视觉样式的更改而不需要改变文档流的情况下发生的制行为。比如颜色的变化、背景图片替换等情况只会导致像素级别的刷新而不影响整体布局结构[^3]。 需要注意的是,尽管单独来看似乎比回流轻量级一些,但如果频繁发生也可能累积成较大的性能瓶颈[^2]。 #### 主要区别 | 特性 | 回流 | | |--------------|-------------------------------|-------------------------| | **定义** | 布局变化引起的新计算 | 只有外观上的变动 | | **触发条件** | 修改了影响布局的因素 | 改变了不影响布局的样式 | | **范围** | 影响较大 | 较小 | | **频率控制** | 应尽量减少 | 同理需加以管理 | 为了提升网页加载速度并改善用户体验,在开发过程中应当采取措施来降低不必要的回流事件的发生几率。可以通过批量处理DOM变更动作、使用虚拟dom技术等方式实现优化目的;另外还可以考虑采用GPU加速特性明显的 CSS 属性如 `transform` `opacity`, 这些不会引起常规意义上的reflow/repaint流程而是交由更高效的图形处理器完成相应工作[^4]。 ```javascript // 减少回流的一个例子:先移除元素再做多次修改最后放回去 let parentElement = document.getElementById('parent'); let childToModify = document.createElement('div'); childToModify.style.width = '200px'; childToModify.style.height = '200px'; childToModify.style.backgroundColor = '#ff0000'; parentElement.appendChild(childToModify); ``` 上述代码展示了如何通过创建新节点而非直接操作现有DOM节点的方式来避免连续性的回流问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值