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
解决方式:
重绘(repaint)和回流(reflow)
- 重绘指当节点需要改变外观但是不会影响布局时发生,比如color
- 回流指当节点的几何属性会布局变化时发生
重绘不一定引起回流,但是回流一定会引发重绘,所以 回流的成本大于重绘
以下几点需要注意:
- 改变window大小
- 改变字体
- 添加、删除、修改样式
- 文字改变
- 定位或者浮动
- 盒模型改变
重绘回流与EventLoop关系
- 当 Eventloop 执行完 Microtasks 后,会判断
document
是否需要更新,因为浏览器是 60Hz 的刷新率,每 16.6ms 才会更新一次。 - 然后判断是否有
resize
或者scroll
事件,有的话会去触发事件,所以resize
和scroll
事件也是至少 16ms 才会触发一次,并且自带节流功能。 - 判断是否触发了 media query
- 更新动画并且发送事件
- 判断是否有全屏操作事件
- 执行
requestAnimationFrame
回调 - 执行
IntersectionObserver
回调,该方法用于判断元素是否可见,可以用于懒加载上,但是兼容性不好 - 更新界面
- 以上就是一帧中可能会做的事情。如果在一帧中有空闲时间,就会去执行
requestIdleCallback
回调。
减少重绘和回流
- 使用transform
- visibility 代替 display:none ,前者引起重绘,后者引起回流
- 不要在循环中获取节点offsetTop等属性(会导致回流)
- 不要使用table布局,小改动会引发整个table回流
- 动画实现速度越快,回流越多,使用requestAnimationFrame
- 将频繁重绘或者回流的节点设置为图层
设置为图层的方法:
- will-change
- 使用video、iframe
总结
在不考虑缓存和优化网络协议的前提下,考虑可以通过哪些方式来最快的渲染页面,也就是常说的 关键路径渲染,这部分也是性能优化中的一块内容
提前DOMContentLoaded时间发生时间,该时间发生后就会生成渲染树渲染,与硬件关系较大,优化空间小
解决方向:
- 从文件大小考虑
- 从script标签考虑
- 从Html,css代码书写考虑
- 从需要下载的内容是否在首屏上使用考虑
css从右向左解析,因此css需要扁平化。html嵌套层级不应该太多,减少嵌套层级