如何去优化浏览器页面?

12/12/2022 加载交互RTT

# 前言

页面优化 => 让页面更快的显示、响应。

# 页面的生存周期

  • 加载阶段:从发出请求 ~ 渲染出完整页面的过程。影响因素有网络、JavaScript
  • 交互阶段:页面加载完毕 ~ 用户交互的整个过程。影响因素主要是JavaScript
  • 关闭阶段:用户发出关闭指令后 ~ 页面清理操作。

# 加载阶段

渲染流水线渲染流水线

并非所有资源都会阻塞页面首次绘制(如图片、音频、视频),但JavaScript、CSS、首次请求的HTML文件会阻塞首次渲染(这三个是关键资源)。

# 核心影响因素

  1. 关键资源个数
  • 内联写JS、CSS => 减少HTTP请求次数
  • 若JS未操作DOM => 标记该JS为defer/async异步加载
  • 若CSS不是构建页面之间必须加载 => 标记CSS link属性为“取消阻止显现”将其转为非关键资源
  1. 关键资源大小
  • 压缩JS、CSS资源
  • 移除HTML、CSS、JS中注释内容
  • 通过上述标记JS、CSS方式减少关键资源数
  1. 请求关键资源需要多少RTT(Round Trip Time)
  • 减少关键资源数 + 减少关键资源大小 => 降低RTT次数
  • 使用CDN减少RTT时长

# RTT

TCP协议传输文件,不是一次传输到服务端的,特性是拆分成一个个数据包来回多次进行传输。

RTT:

  • 发送端发送数据开始 ~ 发送端收到来自接收端的确认的往返时延
  • 一个HTTP数据包14KB左右,一个0.1M的页面文件 <=> 拆成8个包 <=> 需要8个RTT

# 交互阶段

渲染进程渲染一帧渲染引擎流程 优化核心方向:渲染进程渲染帧的速度。交互阶段没有关键资源、构建DOM、CSSOM的过程,一般由JS触发交互动画(重排、重绘、合成)

# 生成帧速度优化

  1. 有的JS函数一次执行时间可能几百毫秒,霸占主线程执行的渲染任务,所以需要减少JS执行时间:
    • 将一次执行函数分解为多个任务(降低一次的执行时间)
    • Web Workers => 将其认为是主线程之外的一个线程,在里面可以执行脚本(没有DOM、CSSOM环境),所以无法用JS访问DOM,将一些跟DOM操作无关的耗时任务丢进Web Workers执行
  2. 避免强制同步布局,正常通过DOM接口添加删除元素后,需要重新计算样式和布局,并且这些操作是异步完成的,就是避免当前任务占用主线程太久。使用JS强制将计算样式和布局操作提前到当前任务中就属于强制同步布局。比如通过JS改变元素高度,本应该异步计算重新布局,但是改变元素后立即通过JS获取改变后的高度,导致渲染引擎只能强制执行一次布局同步获取高度
    • 在修改DOM之前去查询相关值去避免强制同步布局。
  3. 避免布局抖动,指在JS执行过程中,多次执行强制布局和抖动操作,比如在一个循环里面不断读取属性值,每次读取属性值之前都进行了计算样式和布局,内部重复执行计算样式和布局,这会大大影响当前函数的执行效率。
    • 尽量不要在修改DOM结构时去查询一些相关值。
  4. 利用CSS合成动画,合成动画是在合成线程上执行的,不影响主线程。如果能提前知道对某个元素执行动画操作,将其标记为will-change => 告知渲染引擎需要将该元素单独生成一个图层。
  5. 避免频繁的垃圾回收,JS是自动垃圾回收机制,如果在一些函数中频繁创建临时对象,那么垃圾回收器也会频繁地去执行垃圾回收策略 => 发生垃圾回收操作 => 占用主线程 => 影响到其他任务的执行 => 严重的话会掉帧、不流畅。
    • 尽可能优化储存结构,避免小颗粒对象的产生。

# 总结

  • 加载阶段:降低资源大小、数量
  • 交互阶段:避免占用主线程过久
Last Updated: 12/16/2022, 5:36:42 PM