# 前言
页面优化 => 让页面更快的显示、响应。
# 页面的生存周期
- 加载阶段:从发出请求 ~ 渲染出完整页面的过程。影响因素有网络、JavaScript。
- 交互阶段:页面加载完毕 ~ 用户交互的整个过程。影响因素主要是JavaScript。
- 关闭阶段:用户发出关闭指令后 ~ 页面清理操作。
# 加载阶段
并非所有资源都会阻塞页面首次绘制(如图片、音频、视频),但JavaScript、CSS、首次请求的HTML文件会阻塞首次渲染(这三个是关键资源)。
# 核心影响因素
- 关键资源个数
- 内联写JS、CSS => 减少HTTP请求次数
- 若JS未操作DOM => 标记该JS为defer/async异步加载
- 若CSS不是构建页面之间必须加载 => 标记CSS link属性为“取消阻止显现”将其转为非关键资源
- 关键资源大小
- 压缩JS、CSS资源
- 移除HTML、CSS、JS中注释内容
- 通过上述标记JS、CSS方式减少关键资源数
- 请求关键资源需要多少RTT(Round Trip Time)
- 减少关键资源数 + 减少关键资源大小 => 降低RTT次数
- 使用CDN减少RTT时长
# RTT
TCP协议传输文件,不是一次传输到服务端的,特性是拆分成一个个数据包来回多次进行传输。
RTT:
- 发送端发送数据开始 ~ 发送端收到来自接收端的确认的往返时延
- 一个HTTP数据包14KB左右,一个0.1M的页面文件 <=> 拆成8个包 <=> 需要8个RTT
# 交互阶段
渲染进程渲染一帧: 优化核心方向:渲染进程渲染帧的速度。交互阶段没有关键资源、构建DOM、CSSOM的过程,一般由JS触发交互动画(重排、重绘、合成)
# 生成帧速度优化
- 有的JS函数一次执行时间可能几百毫秒,霸占主线程执行的渲染任务,所以需要减少JS执行时间:
- 将一次执行函数分解为多个任务(降低一次的执行时间)
- Web Workers => 将其认为是主线程之外的一个线程,在里面可以执行脚本(没有DOM、CSSOM环境),所以无法用JS访问DOM,将一些跟DOM操作无关的耗时任务丢进Web Workers执行
- 避免强制同步布局,正常通过DOM接口添加删除元素后,需要重新计算样式和布局,并且这些操作是异步完成的,就是避免当前任务占用主线程太久。使用JS强制将计算样式和布局操作提前到当前任务中就属于强制同步布局。比如通过JS改变元素高度,本应该异步计算重新布局,但是改变元素后立即通过JS获取改变后的高度,导致渲染引擎只能强制执行一次布局同步获取高度。
- 在修改DOM之前去查询相关值去避免强制同步布局。
- 避免布局抖动,指在JS执行过程中,多次执行强制布局和抖动操作,比如在一个循环里面不断读取属性值,每次读取属性值之前都进行了计算样式和布局,内部重复执行计算样式和布局,这会大大影响当前函数的执行效率。
- 尽量不要在修改DOM结构时去查询一些相关值。
- 利用CSS合成动画,合成动画是在合成线程上执行的,不影响主线程。如果能提前知道对某个元素执行动画操作,将其标记为will-change => 告知渲染引擎需要将该元素单独生成一个图层。
- 避免频繁的垃圾回收,JS是自动垃圾回收机制,如果在一些函数中频繁创建临时对象,那么垃圾回收器也会频繁地去执行垃圾回收策略 => 发生垃圾回收操作 => 占用主线程 => 影响到其他任务的执行 => 严重的话会掉帧、不流畅。
- 尽可能优化储存结构,避免小颗粒对象的产生。
# 总结
- 加载阶段:降低资源大小、数量
- 交互阶段:避免占用主线程过久