前端性能优化
首屏加载
静态资源
图片压缩
图标压缩
字体压缩
分析包体积构成
js/css minify & purify
提取首屏所需的 css、js,延迟非首屏资源
网络传输
CDN: Brotli/Gzip 压缩
cache-control 头
http2
浏览器相关
使用 meta renderer 标签
CRP 优化
Critical Rendering Path
link 标签前置 script 标签置底
DOM 树扁平
减少阻塞的 css
- 使用 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 条
优化的机会
- 消除阻塞渲染的资源
- 使用正确大小的图片
- 延迟离屏的图片
- 减小 css
- 减小 js
- 移除未使用的 css
- 更有效地编码图片
- 使用下一代的图片编码方案
- 开启 http 压缩
- 预连接指定的域
- 减少 TTFB 时间
- 避免多页重定向
- 预加载关键资源
- 使用视频来代替动画内容
- 减小三方代码的影响,如何更有效地加载第三方代码
- 避免非合成的动画
实时渲染优化
多线程
使用 web worker 或者 rAF 分离计算
减少样式重新计算成本
避免布局抖动
- 使用 flex
- 高压力点避免任何布局相关任务
- 避免强制布局
- 修改布局信息时,可以用 display:none 暂时移出 DOM 树
优化重绘效率
- 避免使用性能高消耗的阴影等 css3
- 使用 Chrome DevTools 检查重绘区域
- 避免多个动画
优化合成效率
- 使用仅触发 Composite 的 css 属性(transform/opacity)
- 提升图层
- 布局易变动
- 重绘代价高、频率高
- 可接受额外内存开销
- 触发提升为合成层的条件
高压力点去抖动
- 输入事件
- 滚动事件
低端机兼容
- 去除高消耗动画
- 优化高压力 cpu、io 计算
引擎优化
JIT
WebAssembly
绘制优化
canvas
- 离屏渲染 + 缓存部分元素
- 分层画布:z-index 实现多层 canvas 叠绘
- 渲染差异帧
- 避免使用浮点数与图像缩放:使用 transfrom 将运算转至 GPU
- 关闭透明度:getContext (‘2d’, {alpha: false})
- 减少模糊和阴影的使用
SVG
- 线上优化工具 SVGOMG
- lllustrator 中使用 SVG 滤镜 (应避免使用滤镜或渐变)
- 不可交互元素设置 pointer-event: none
- 使用 Defs 标签缓存复杂 path 渲染
- Fill + Fill > Fill + Stroke
- SVG 服务端渲染
WebGl
- Three.js 使用建议
- WebGl & Canvas 开发优化策略
- WebGL 使用注意事项和浏览器支持
转化工具
性能指标
帧率、丢帧与流畅度概念
RAIL 模型
用户为中心的性能模型,提供了对能提升性能的结构。拆分了用户体验为几个关键的操作(比如点击、滚动,加载等)。
RAIL 全称为:Response、Animation、Idle 和 Load。
用户感觉视觉停留:
- 0-16ms:用户非常擅长跟踪运动,当动画不流畅时,他们会不喜欢它。 只要每秒渲染 60 个新帧,他们就能感觉到动画的流畅性。 每帧 16 毫秒,包括浏览器将新帧绘制到屏幕上所花费的时间,而应用程序大约需要 10 毫秒才能生成一帧。
- 0-100ms:在此时间窗口内响应用户的操作,用户会感觉到结果是即时的。 当时间更长时,操作与反应之间的联系就被打破了。
- 100-1000ms:在此窗口中,会感觉该操作是自然连续的过程的一部分。 对于网络上的大多数用户而言,加载页面或更改视图是一项任务。
- 1000ms and more:超过 1 秒,用户就对操作失去了关注。
- 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
- Chrome DevTools
- Lighthouse
- WebPageTest
垂直同步 FreeSynx G-Sync 区别
流畅感知原理
- 视觉残留:100ms
- 似动现象:20ms-1s
- 临界闪烁融合阈值:50Hz-100Hz
渐进式渲染指标 TODO
相关经验信息
- 卡顿 = 帧延迟抖动(>20ms)=> 需要降低帧绘制成本,锁 60fps
- 抖动 = 帧间丢失信息量过高 => 节流,提升帧率到 60fps
- rAF/css3 均与显示器刷新率同步,rAF 可控而 css3 不可控
- 文字 / 位置动画(scroll,touch 等)应该保持最大帧率(避免使用 passive: false)
- 颜色 / 形状动画可锁帧,节约性能
- 在必须逐步加载时采用渐进式渲染
- 交互响应应控制在 100ms 内,不满足条件时提供视觉反馈(比如 loading)
相关工具
渲染原理
浏览器工作线程
- iframe 使用独立渲染进程
- 输入、滚动事件监听会与主线程通信
渲染管线
样式重新计算
- css 默认继承属性
- css 渲染原理
布局与回流
绘制
- 影响绘制性能的属性
- transform rotate
- gradients
- shadow
- border-radius
- 层叠上下文与层叠顺序
- canvas 重绘时依据改变内容决定重绘区域大小
合成层、创建合成层
- Document
- 能够提升为合成层的 css 属性、html 标签
- css 属性在不同浏览器内核中触发的渲染管线层级
调试工具
首屏性能
LightHouse(Audits)
- 检查 SEO 优化
- 检查网页潜在阅读障碍
- 避免使用过时或不推荐的 api
- 不使用 http 的资源
- 审查首屏 Metrics 指标
- 未使用的 css 引用
- 检查资源压缩
- 检查 CRP
- 检查是否符合 PWA
渲染性能
- 使用 Performance、Performance Monitor 考察性能开销
- 侦测 js 瓶颈段
- 检查强制布局同步问题 FSL
- 监视内存开销
- 查看主线程、交互线程、光栅线程
- 分析渲染管线耗时比例
- 使用 Rendering 查看渲染开销
- 重绘区域
- 显示层边缘
- 滚动响应问题区域检查
- 使用 Layers 查看合成层开销
- 使用 Animations 调试 css3 动画
- 使用 Coverage 检查当前页面未使用的 js、css 代码