前端性能优化

首屏加载

静态资源

图片压缩

  1. imagemin: 压缩并导出渐进式 JPEG/WebP
  2. 图像元信息清除
  3. tinyPNG
  4. 替换大 GIF 为视频,可以使用 FFMpeg
  5. 图片选择

图标压缩

  1. 图标神器
  2. 创建自己的 iconFont

字体压缩

  1. fontmin 静态字体压缩
  2. woff2 字体格式压缩工具

分析包体积构成

  1. webpack-bundle-analyzer
  2. 代码拆分

js/css minify & purify

提取首屏所需的 css、js,延迟非首屏资源

网络传输

CDN: Brotli/Gzip 压缩

cache-control 头

http2

浏览器相关

使用 meta renderer 标签

CRP 优化

Critical Rendering Path

DOM 树扁平

减少阻塞的 css

  1. 使用 Chrome DevTools 中 Coverage 查看未使用的 css 和 js

使用 LightHouse 审核关键渲染路径

使用 preload、prefetch 微调资源优先级

使用 defer 优化 script 解析,减少首屏阻塞

懒加载

使用 InteractionObserver 监听元素是否在特定区域

滚动监听、resize 等

用视频代替 gif 并设置 <\video>\ preload 为 none

代码拆分 (以 vue 为例)

在首屏后加载其他非首屏资源

骨架屏

应用离线化

web storage

service worker

实践

WebView 加载优化

数据预加载 – 打开 webview 的同时请求接口数据

http transfer-encoding: chunked 提升 TTFB

雅虎 14 条

优化的机会

  1. 消除阻塞渲染的资源
  2. 使用正确大小的图片
  3. 延迟离屏的图片
  4. 减小 css
  5. 减小 js
  6. 移除未使用的 css
  7. 更有效地编码图片
  8. 使用下一代的图片编码方案
  9. 开启 http 压缩
  10. 预连接指定的域
  11. 减少 TTFB 时间
  12. 避免多页重定向
  13. 预加载关键资源
  14. 使用视频来代替动画内容
  15. 减小三方代码的影响如何更有效地加载第三方代码
  16. 避免非合成的动画

实时渲染优化

图解 Chrome

多线程

使用 web worker 或者 rAF 分离计算

减少样式重新计算成本

避免布局抖动

  1. 使用 flex
  2. 高压力点避免任何布局相关任务
  3. 避免强制布局
    1. 使用上一帧缓存的布局信息
    2. 禁止频繁读写布局信息
    3. 使用 FastDom 优化 dom 读写
    4. 使用 Chrome Performance 检查 FSL
  4. 修改布局信息时,可以用 display:none 暂时移出 DOM 树

优化重绘效率

  1. 避免使用性能高消耗的阴影等 css3
  2. 使用 Chrome DevTools 检查重绘区域
  3. 避免多个动画

优化合成效率

  1. 使用仅触发 Composite 的 css 属性(transform/opacity)
  2. 提升图层
    1. 布局易变动
    2. 重绘代价高、频率高
    3. 可接受额外内存开销
    4. 触发提升为合成层的条件

高压力点去抖动

  1. 输入事件
  2. 滚动事件

低端机兼容

  1. 去除高消耗动画
  2. 优化高压力 cpu、io 计算

引擎优化

JIT

WebAssembly

绘制优化

canvas

  1. 离屏渲染 + 缓存部分元素
  2. 分层画布:z-index 实现多层 canvas 叠绘
  3. 渲染差异帧
  4. 避免使用浮点数与图像缩放:使用 transfrom 将运算转至 GPU
  5. 关闭透明度:getContext (‘2d’, {alpha: false})
  6. 减少模糊和阴影的使用

SVG

  1. 线上优化工具 SVGOMG
  2. lllustrator 中使用 SVG 滤镜 (应避免使用滤镜或渐变)
  3. 不可交互元素设置 pointer-event: none
  4. 使用 Defs 标签缓存复杂 path 渲染
  5. Fill + Fill > Fill + Stroke
  6. SVG 服务端渲染

WebGl

  1. Three.js 使用建议
  2. WebGl & Canvas 开发优化策略
  3. WebGL 使用注意事项和浏览器支持

转化工具

  1. SVG2Canvas
  2. HTML2Canvas

性能指标

帧率、丢帧与流畅度概念

RAIL 模型

用户为中心的性能模型,提供了对能提升性能的结构。拆分了用户体验为几个关键的操作(比如点击、滚动,加载等)。
RAIL 全称为:Response、Animation、Idle 和 Load。

用户感觉视觉停留:

  1. 0-16ms:用户非常擅长跟踪运动,当动画不流畅时,他们会不喜欢它。 只要每秒渲染 60 个新帧,他们就能感觉到动画的流畅性。 每帧 16 毫秒,包括浏览器将新帧绘制到屏幕上所花费的时间,而应用程序大约需要 10 毫秒才能生成一帧。
  2. 0-100ms:在此时间窗口内响应用户的操作,用户会感觉到结果是即时的。 当时间更长时,操作与反应之间的联系就被打破了。
  3. 100-1000ms:在此窗口中,会感觉该操作是自然连续的过程的一部分。 对于网络上的大多数用户而言,加载页面或更改视图是一项任务。
  4. 1000ms and more:超过 1 秒,用户就对操作失去了关注。
  5. 10s and more:超过 10 秒,用户就会沮丧,并且很可能丢弃任务。可能不会再回来了。。

目标和指导

  • 目标:关键的性能指标与用户体验相关。比如,点击后在 100ms 内绘制。由于人类的感知是相对恒定的,所以他们的目标在很长时间内不会改变。
  • 指导:帮助你实现目标的建议。它们可能跟设备、网络状态等有关,并且会随时间而改变。

Response:在 50ms 内响应事件

目标:在 100ms 内完成用户的输入转换,这样用户会觉得他们的交互是连续的。

指导:

  • 为了保证在 100ms 内可见的响应,处理用户的输入应该在 50ms 内处理完成。包括绝大多数的输入,比如点击按钮,切换表单的控制项(radio、checkbox、select 等),或者是动画。 不适用于拖动或者滚动。
  • 不是总需要立即响应用户的输入,虽然这听起来有点反直觉。你可以在这 100ms 内处理一些其他高消耗的工作,但是注意不要阻塞用户。如果可能,在后台工作。
  • 对于需要超过 50ms 完成的任务,总是提供反馈。

Animation:在 10ms 内完成一帧

目标:

  • 在 10ms 内完成一帧。从技术上讲,最多 16ms 需要完成一帧,但浏览器需要 6ms 去渲染每一帧,所以要在 10ms 内完成一帧
  • 视觉上的流畅。用户会感觉到帧率的变化。

指导:

  • 高压力点比如动画时,什么都不做;在绝对最低时更不能做。尽可能在 100ms 内响应预先计算的高消耗工作,这能让你最大程度达到 60fps。
  • 通过 Rendering Performance 工具查看动画的优化策略。

认清动画:

  • 视觉动画,比如进入、移出、tween,加载指示器等;
  • 滚动。用户拖动页面,开始滚动,然后放开,页面会继续滚动。
  • 拖动。动画经常发生在用户的交互上。比如平移地图上或者缩放。

Idle:最大化空闲时间

目标:最大化空闲时间以增加页面在 50ms 内响应用户输入的几率。
指导:

  • 使用空闲时间完成延迟的工作。比如,对于页面首次加载,可以先加载尽量少的数据,再在空闲时间加载其他数据。
  • 在 50ms 内的空闲时间内去完成任务。超过 50ms,你可能就会影响页面在 50ms 内响应用户输入。
  • 空闲时间内有工作时,如果用户在这时产生交互,需要将用户的交互提高为最高优先级,先中断当前的空闲时间任务。(TODO// HOW)

Load:分发内容并在 5s 内可交互

目标(这些目标会随着时间而改变):

  • 针对设备、网络能力,优化加载性能。一个好的目标就是 5s 内可交互(中端手机,slow 3G)
  • 对于后续的加载,期望在 2s 内完成。

指导:

  • 测试加载性能。
  • 需要明确的是,你的用户的设备可能是 2G、3G、4G,实际上有效连接速度会明显更慢。
  • 消除渲染阻塞的资源
  • 不必要进行完整加载。可以懒加载图片、代码拆分等,以及 web.dev 上的建议

测量 RAIL

  1. Chrome DevTools
  2. Lighthouse
  3. WebPageTest

垂直同步 FreeSynx G-Sync 区别

流畅感知原理

  1. 视觉残留:100ms
  2. 似动现象:20ms-1s
  3. 临界闪烁融合阈值:50Hz-100Hz

渐进式渲染指标 TODO

  1. speed index
  2. FP/FCP/FMP/TTI/TTCI
  3. 使用 performance 接口衡量指标

相关经验信息

  1. 卡顿 = 帧延迟抖动(>20ms)=> 需要降低帧绘制成本,锁 60fps
  2. 抖动 = 帧间丢失信息量过高 => 节流,提升帧率到 60fps
  3. rAF/css3 均与显示器刷新率同步,rAF 可控而 css3 不可控
  4. 文字 / 位置动画(scroll,touch 等)应该保持最大帧率(避免使用 passive: false)
  5. 颜色 / 形状动画可锁帧,节约性能
  6. 在必须逐步加载时采用渐进式渲染
  7. 交互响应应控制在 100ms 内,不满足条件时提供视觉反馈(比如 loading)

相关工具

lighthouse 分数计算器


渲染原理

浏览器工作线程

  1. iframe 使用独立渲染进程
  2. 输入、滚动事件监听会与主线程通信

渲染管线

样式重新计算

  1. css 默认继承属性
  2. css 渲染原理

布局与回流

  1. 渲染树构建原理
  2. BFC
  3. 清除浮动
  4. 影响布局性能的属性

绘制

  1. 影响绘制性能的属性
    1. transform rotate
    2. gradients
    3. shadow
    4. border-radius
  2. 层叠上下文与层叠顺序
  3. canvas 重绘时依据改变内容决定重绘区域大小

合成层、创建合成层

  1. Document
  2. 能够提升为合成层的 css 属性、html 标签
  3. css 属性在不同浏览器内核中触发的渲染管线层级

调试工具

首屏性能

LightHouse(Audits)

  1. 检查 SEO 优化
  2. 检查网页潜在阅读障碍
  3. 避免使用过时或不推荐的 api
  4. 不使用 http 的资源
  5. 审查首屏 Metrics 指标
    1. 未使用的 css 引用
    2. 检查资源压缩
    3. 检查 CRP
  6. 检查是否符合 PWA

渲染性能

  1. 使用 Performance、Performance Monitor 考察性能开销
    1. 侦测 js 瓶颈段
    2. 检查强制布局同步问题 FSL
    3. 监视内存开销
    4. 查看主线程、交互线程、光栅线程
    5. 分析渲染管线耗时比例
  2. 使用 Rendering 查看渲染开销
    1. 重绘区域
    2. 显示层边缘
    3. 滚动响应问题区域检查
  3. 使用 Layers 查看合成层开销
  4. 使用 Animations 调试 css3 动画
  5. 使用 Coverage 检查当前页面未使用的 js、css 代码

参考

Google 优化