reFlow和rePaint

本文详细介绍了浏览器渲染HTML的过程,包括解析HTML、CSSOM和JS执行、样式计算、布局、分层、绘制等步骤。接着,文章重点讨论了reFlow和rePaint的概念,reFlow涉及布局树的重新计算,而rePaint则是重新绘制元素的可视部分。通过理解这两者,可以优化前端性能,如利用transform提高效率,因为它仅影响绘制阶段且通常由GPU处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

浏览器渲染原理

想要理解reFlow和rePaint,就需要先明白浏览器渲染一个html字符串文档的流程。打开一个浏览器标签页,地址栏输入地址回车之后,浏览器进程会开启一个网络进程,获取对应资源,获取到之后会开启一个对应的渲染进程,渲染进程会开启渲染主进程,此时能拿到网络返回的HTML字符串文本,接下来开始浏览器渲染的8个大步骤。

  1. 解析HTML,首先解析结果会是一个DOM树和一个CSS Object Model树。
    • 解析过程中遇到 CSS 解析 CSS,遇到 JS 执行 JS。为了提高解析效率,浏览器在开始解析前,会启动一个预解析的线程,优先下载外部 CSS 文件和 外部的 JS 文件。
    • 如果渲染主线程解析到link位置,此时外部的 CSS 文件还没有下载解析好,渲染主线程不会等待,继续解析后续的 HTML。这是因为下载和解析 CSS 的工作是在预解析线程中进行的。这就是 CSS 不会阻塞 HTML 解析的根本原因。
    • 如果主线程解析到script位置,会停止解析 HTML,转而等待 JS 文件下载好,并将js文件中的全局代码解析执行完成后,才能继续解析 HTML。这是因为 JS 代码的执行过程可能会修改当前的 DOM 节点,所以 DOM 树的生成必须暂停。这就是 JS 会阻塞 HTML 解析的根本原因。
    • 第一步完成后,会得到 DOM 树和 CSSOM 树,浏览器的默认样式、内部样式、外部样式、行内样式均会包含在 CSSOM 树中。
  2. 样式计算(Computed Style),主线程会遍历 DOM 树,依次为树中的每个节点计算出它最终的样式,称之为 Computed Style。在过程中,很多预设值会变成绝对值,比如red会变成rgb,相对单位rem、em会变成绝对单位px,可以在浏览器检查元素的computed卡片查看,可以看到每个元素都会有完整的全部样式属性。这一步完成后,会得到一棵带有样式的 DOM 树。
  3. 对样式计算结果进行处理,生成Layout树,称为布局。layout树包括元素的尺寸、位置信息,处理过程中如display:none隐藏节点不会生成到layout树上,:before这些伪类元素在DOM树上不存在,但是会在Layout树上,所以DOM树和Layout树不一定是一一对应的。
  4. 分层(Layer),如果一个页面很大,每次有更新时重新布局整个页面太过耗时,所以浏览器会有一套算法自动进行分层,主要作用就是把页面拆解成不同的图层,当页面在视觉上发生变化时,这些变化其实只会影响某一个图层,其他图层不受影响,更高效的完成绘制。
    • 拆分图层默认情况下是浏览器决定的,浏览器主要分析元素之间是否互相影响,如果某些元素对其他元素造成的影响很大,就会被浏览器提取成单独的图层。
    • 我们也可以主动的把某些元素提取到单独的图层,但是也不是拆分越多越好,因为图层越多开销也越高,从而适得其反影响网页的性能。因此只把特定的,能达到效果的元素提到一个图层中。
    • 滚动条、堆叠上下文、transform、opacity 等样式都会影响分层结果,在元素上设置willChange属性可以主动分层,值为’transform’表示提示浏览器后续这个元素的transform属性会频繁变动,让浏览器自动分层。
  5. 绘制(Paint),为每一层生成如何进行绘制的指令集,类似canvas,输入指令 生成结果,事实上canvas就利用了浏览器内核的绘制核心。

---- 到此为止,渲染主进程工作暂时结束,剩下的步骤交给其他进程完成。

  1. 合成线程-分块(Tiling),之前分的图层也很大,浏览器会对图层进行分块,将每一层分为多个小的区域。分块的工作是同时交给多个线程同时进行的。
  2. 合成线程-光栅化(Raster),光栅化是将每一个块变成位图,位图信息包括位置、尺寸、颜色等。优先处理靠近视口的块。过程中会用到GPU进行加速,提升光栅化速度。
  3. 画(Draw),合成线程计算出每个位图在屏幕的位置,交给GPU进行最终呈现。
    浏览器渲染原理

reFlow重新布局

reFlow 的本质就是当进行了会影响布局树的操作后,比如修改元素位置(offsetWidth等)、尺寸(宽高)、字体大小等,需要重新计算布局树Layout。

浏览器为了避免连续的多次操作导致布局树反复计算,比如第一行修改了元素宽度,第二行修改了元素高度,第三行修改了其他尺寸,浏览器会合并这些操作,并放到消息队列,等 JS 代码全部完成后再进行统一计算。所以,改动属性造成的 reFlow 是异步完成的。

但是代码书写过程中,我修改完可能需要立即获取当前的最新宽度,此时当 JS 获取布局属性时,就可能造成无法获取到最新的布局信息,浏览器在反复权衡下,最终决定当有获取属性的代码时立即 reFlow。

rePaint重绘

repaint 的本质就是重新根据分层信息计算了绘制指令。当改动了可见样式后,比如颜色,就需要重新绘制像素信息,颜色跟尺寸位置无关,不需要重新 生成Layout树,所以会重新计算绘制指令,引发 rePaint。

由于元素的布局信息也属于可见样式,所以 reFlow 一定会引起 rePaint。

扩展信息

为什么 transform 的效率高?

因为 transform 既不会影响布局Layout树也不会影响Paint绘制指令,它影响的只是渲染流程的最后一个「Draw」阶段,一般在GPU中处理,速度很快。由于 draw 阶段在合成线程中,所以 transform 的变化几乎不会影响渲染主线程。反之,渲染主线程无论如何忙碌,也不会影响 transform 的变化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值