浏览器渲染原理与性能优化

HTML、CSS渲染过程

DOM构建过程:字符数据->字符串->Token(标记)->Node->DOM树

CSSOM构建过程:字符数据->字符串->Token(标记)->Node->CSSOM树

DOM树和CSSOM树组合为渲染树
display:none 不会在渲染树中显示

为什么操作DOM慢?

DOM树属于渲染引擎,JS属于JS引擎,操作DOM树要在两个引擎的线程之间通信

插入大数据量DOM节点,如何做到不卡顿?

方式1:采用requestAnimation循环插入DOM
方式2:虚拟滚动,只展示用户看到的DOM

什么情况阻塞渲染?

当浏览器解析到script标签,会暂停DOM构建,进行脚本下载和解析,完成后继续构建DOM
解决方式:

  1. 将script标签放到body底部
  2. 加defer属性,浏览器会并行下载js文件,在HTML解析完成后执行
  3. 加async属性,表示JS下载和解析不会影响渲染执行

重绘(repaint)和回流(reflow)

  1. 重绘指当节点需要改变外观但是不会影响布局时发生,比如color
  2. 回流指当节点的几何属性会布局变化时发生

重绘不一定引起回流,但是回流一定会引发重绘,所以 回流的成本大于重绘

以下几点需要注意:

  1. 改变window大小
  2. 改变字体
  3. 添加、删除、修改样式
  4. 文字改变
  5. 定位或者浮动
  6. 盒模型改变

重绘回流与EventLoop关系

  1. 当 Eventloop 执行完 Microtasks 后,会判断 document 是否需要更新,因为浏览器是 60Hz 的刷新率,每 16.6ms 才会更新一次。
  2. 然后判断是否有 resize 或者 scroll 事件,有的话会去触发事件,所以 resizescroll 事件也是至少 16ms 才会触发一次,并且自带节流功能。
  3. 判断是否触发了 media query
  4. 更新动画并且发送事件
  5. 判断是否有全屏操作事件
  6. 执行 requestAnimationFrame 回调
  7. 执行 IntersectionObserver 回调,该方法用于判断元素是否可见,可以用于懒加载上,但是兼容性不好
  8. 更新界面
  9. 以上就是一帧中可能会做的事情。如果在一帧中有空闲时间,就会去执行 requestIdleCallback 回调。

减少重绘和回流

  1. 使用transform
  2. visibility 代替 display:none ,前者引起重绘,后者引起回流
  3. 不要在循环中获取节点offsetTop等属性(会导致回流)
  4. 不要使用table布局,小改动会引发整个table回流
  5. 动画实现速度越快,回流越多,使用requestAnimationFrame
  6. 将频繁重绘或者回流的节点设置为图层

设置为图层的方法:

  1. will-change
  2. 使用video、iframe

总结

在不考虑缓存和优化网络协议的前提下,考虑可以通过哪些方式来最快的渲染页面,也就是常说的 关键路径渲染,这部分也是性能优化中的一块内容

提前DOMContentLoaded时间发生时间,该时间发生后就会生成渲染树渲染,与硬件关系较大,优化空间小

解决方向:

  1. 从文件大小考虑
  2. 从script标签考虑
  3. 从Html,css代码书写考虑
  4. 从需要下载的内容是否在首屏上使用考虑

css从右向左解析,因此css需要扁平化。html嵌套层级不应该太多,减少嵌套层级