一、浏览器渲染原理和关键渲染路径
- 浏览器构建渲染树,
DOM
树和CSSDOM
树合成为Render Tree
渲染树。 - 浏览器的渲染流程,如下所示:
JavaScript -> Style -> Layout -> Paint -> Composite
。 - 布局与绘制,如下所示:
- 渲染树只包含网页需要的节点
- 布局计算每个节点精确的位置和大写,盒模型
- 绘制是像素化每个节点的过程
- 影响回流的操作,如下所示:
- 添加、删除元素
- 操作
styles
display: none
offsetLeft、scrollTop、clientWidth
- 移动元素位置
- 修改浏览器大小、字体大小
- 避免布局抖动
Layout thrashing
,如下所示:
- 避免回流
- 读写分离
- 使用
FastDOM
可以批量的对DOM
的读写操作,进行性能提升。
二、复合线程、图层及优化
- 复合线程,如下所示:
- 将页面拆分图层进行绘制再进行复合
- 利用
DevTools
了解网页的图层拆分情况 - 哪些样式仅影响复合
- 减少重绘的方案
- 利用
DevTools
识别paint
的瓶颈 - 利用
will-change
创建新的图层
- 对于事件处理函数,可以使用防抖处理。
React
时间调度的基本原理,如下所示:
requestIdleCallback
的问题- 通过
rAF
模拟rIC
三、JS 开销及优化
JavaScript
的开销缩短解析时间,JavaScript
的开销会存在于加载、执行、解析和编译中。JavaScript
开销减少的方案,如下所示:
Code splitting
代码拆分,按需加载Tree shaking
代码减重
JavaScript
减少主线程工作量,如下所示:
- 避免长任务
- 避免超过
1KB
的行间脚本 - 使用
rAF
和rIc
进行时间调度
- 对于渐进式启动
Progressive Bootstrapping
,可见不可交互与最小可交互资源集。 V8
优化机制,如下所示:
- 脚本流
- 字节码缓存
- 懒解析
- 抽象语法树,如下所示:
- 源码 -> 抽象语法树 -> 字节码
Bytecode
-> 机器码 - 编译过程会进行优化
- 运行时可能发生反优化
- 函数的解析方式,如下所示:
lazy parsing
懒解析、eager parsing
饥饿解析- 利用
Optimize.js
优化初次加载时间
- 对象优化,如下
- 以相同顺序初始化对象成员,避免隐藏类的调整
- 实例化后避免添加新属性
- 尽量使用
Array
代替array-like
对象 - 避免读取超过数组的长度
- 避免元素类型转换
四、HTML 和 CSS 优化
HTML
优化,如下所示:
- 减小
iframes
使用 - 避免
table
布局 - 压缩空白符
- 删除注释
- 避免节点深层级嵌套
CSS
和Javascript
尽量外链- 删除元素默认属性
- 如果借助工具,可以使用
html-minifier
去压缩HTML
。 - 对于样式计算开销,可以利用
DevTools
测量样式计算开销。 - 对于
CSS
优化,如下所示:
- 降低
CSS
对渲染的阻塞 - 利用
GPU
进行完成动画 - 使用
contain
属性 - 使用
font-display
属性