前端性能优化之——预备篇
前言
趁空闲时间又开了个新坑,记录下目前自己遇到过的一些前端性能优化相关经验总结
希望有朝一日我能把所有还在 draft 阶段的坑都填了
这次准备发一系列文档,预计在6月前完工。
因写内存泄漏文档时发现坑挖太大了不好填,于是这次改进为挖多个小坑一个个填
内存泄漏文档的坑也准备拆一下,不然填不动了,希望有朝一日能完工
何时应该考虑优化性能
性能优化的目标
先考虑这样的例子:玩游戏的时候掉帧,会让玩家很难受,而当开启显卡的帧生成功能时,尽管它实际上增加了输入和画面延迟,但玩家几乎感知不到,反而会感觉游戏的体验更流畅了。而帧生成做的事情,其实是将帧数提升到玩家的舒适范围内,并且保证玩家尽可能感知不到额外的输入延迟,对玩家而言就是游戏性能变得更优了。
类似地,当我们自己使用软件时,一般只有在出现明显卡顿或者延迟的时候才会感知到。
故性能优化的目标可以概括为:将延迟和卡顿降低到用户的可接受范围内。
优化的时机
先上结论:绝大部分情况下,只有出现性能瓶颈的时候才应该考虑优化性能。
性能优化的投入与回报类似一个对数曲线,越往后,付出的成本和回报就越不成正比。因此,如何平衡软件性能与开发成本通常是我们每个开发者都要面临的问题。当然,如果你是个人开发者 or 技术爱好者,那么保证自己的产品在每个细节上都做到性能优秀可能更加适合,但如果是一个全职开发者,并且公司是业务驱动而非技术驱动,那么保证自己可以快速实现功能可能是更重要的。
大部分情况下公司都是业务驱动,即使有些公司声称自己是技术驱动的,个人认为真正的技术驱动公司只会在老板不在乎利润的情况下出现,almost impossible 🙁
因此,在出现性能瓶颈,也就是用户能感知到卡顿或者延迟的时候再去考虑性能优化,是实际开发工作中的性价比之选。
常见前端性能指标
指标概览
让我们先来看一下目前在前端领域都有哪些常见的指标(留下印象即可):
- First Contentful Paint (FCP):首次内容绘制,衡量从网页开始加载到网页任何部分呈现在屏幕上所用的时间
- Largest Contentful Paint (LCP):最大内容绘制,衡量从网页开始加载到屏幕上渲染最大的文本块或图片/视频元素所用的时间
- First Input Delay (FID):首次输入延迟,衡量从用户首次与页面互动(点击链接、点按按钮或使用由 JavaScript 提供支持的自定义控件)到浏览器实际能够响应该互动的时间
- Interaction to Next Paint (INP):衡量与网页进行每次点按、点击或键盘交互的延迟时间,并根据互动次数选择该网页最差的互动延迟时间(或接近最高延迟时间)作为单个代表性值,以描述网页的整体响应速度
- Time to Interactive (TTI):可交互时间,衡量的是从网页开始加载到视觉呈现、其初始脚本(若有)已加载且能够快速可靠地响应用户输入的时间
- Total Blocking Time (TBT):总阻塞时间,测量 FCP 和 TTI 之间的总时间,在此期间,主线程处于屏蔽状态的时间够长,足以阻止输入响应
- Cumulative Layout Shift (CLS):衡量从页面开始加载到其生命周期状态更改为隐藏之间发生的所有意外布局偏移的累计得分
- Time to First Byte (TTFB):首字节时间,测量网络使用资源的第一个字节响应用户请求所需的时间
大伙应该也猜到了,在实际开发中关注那么多指标是不现实的,所以我们需要了解哪些指标的优先级最高,需要重点关注
核心性能指标 – Core Web Vitals
下面的指标定义和图片资源都来自web.dev网站,博主只提炼了一些主要信息,感兴趣的读者可自行前往阅读
Core Web Vitals 是Google提出的用于衡量页面用户体验质量的核心性能指标,影响搜索引擎排名(SEO)。
其包含的指标有:LCP、INP、CLS,下面我们一起来详细了解下这些指标
LCP
定义
视口内可见的最大图片、文本或视频的渲染时间,用于衡量页面的加载性能
计算原理
- 候选元素类型:
<img>
标签(包含SVG内的<img>
)<video>
标签- 通过
url()
加载的背景图 - 包含文本的块级元素(如
p
div
h1
等)
- 计算元素面积:
- 计算元素在视口内可见部分的面积
- 忽略超出视口的区域、被遮挡或透明的内容
- 记录时间点
- 元素的渲染时间等于其资源加载完成并渲染到屏幕的时间
- 对于文本块,时间点是字体加载完且布局稳定后
- 动态更新
- 在页面加载过程中,如果出现更大的元素,LCP候选元素会更新
示例:
INP
定义
通过观察用户访问网页期间发生的所有点击、点按和键盘互动的延迟时间,其中最长的时间报告为INP,用于评估网页对用户互动的总体响应情况
计算原理
- 观察交互类型
- 使用鼠标点击
- 在触摸屏设备上点按
- 按实体键盘或屏幕键盘上的按键
- 计算交互延迟(参考下图)
- 输入延迟(Input Delay):从交互触发到浏览器主线程开始处理事件的时间(类似 FID)
- 处理时间(Processing Duration):事件处理函数(如 onClick)的执行耗时
- 呈现延迟(Presentation Delay):浏览器渲染下一帧(next paint)的时间
为了更好地衡量互动量较高的网页的实际响应速度,计算时会忽略每 50 次互动中的一次最高互动
与FID的区别
- FID 仅衡量网页上首次互动的输入延迟,INP 通过观察网页上的所有互动,取其中时间最长的值
- FID 是一种加载响应能力指标,旨在评估网页给用户的第一印象;INP 是一种更可靠的总体响应能力指标,无论网页互动发生在网页生命周期的什么时间点,它都能反映网页的总体响应能力
CLS
定义
相比前两个指标,CLS将会更复杂一点,但请放轻松&保持耐心,真正理解后会发现这个概念其实也很简单
CLS指页面生命周期内所有意外布局偏移的累积分数,用于评估页面的视觉稳定性
计算原理
基本公式
布局偏移分数(layout shift score)由一次布局偏移的影响分数(impact fraction)和距离分数(distance fraction)相乘得出
即layout shift score = impact fraction * distance fraction
影响分数
定义:偏移元素在视口中影响的可视区域比例
计算方式:影响分数 = 偏移前面积 ∪ 偏移后面积 / 视口总面积
示例:
在上图中,有一个元素在一个帧中占据了视口的一半。然后,在下一个画面中,该元素会向下移动视口高度的 25%。红色虚线矩形表示元素在两个帧中的可见区域的并集,在本例中,该区域占整个视口的 75%,因此其影响百分比为 0.75
距离分数
定义:偏移元素在视口中移动的最大相对距离(垂直或水平方向)
计算方式:距离分数 = 移动距离 / 视口对应方向尺寸(高度或宽度)
示例:
在上面的示例中,视口的最大尺寸是高度,并且不稳定的元素移动了视口高度的 25%,因此距离分数为 0.25
计算CLS
基于上面所说的内容,我们就可以计算CLS了
示例:
- 在上图的第一帧中,显示了针对动物的 API 请求的四个结果,这些结果按字母顺序排序。在第二个画面中,系统会向已排序的列表中添加更多结果
- 列表中的第一项(“猫”)在帧之间不会更改其起始位置,因此是稳定的。同样,添加到列表的新项之前不在 DOM 中,因此它们的起始位置也不会发生变化。但是,标记为“狗”“马”和“斑马”的项都将其起始位置移到了其他位置,因此它们是不稳定的元素
- 同样,红色虚线矩形表示这三个不稳定元素的“前”和“后”区域的并集,在本例中,这大约占视口区域的 60%,影响分数为
0.60
- 箭头表示不稳定元素从其起始位置移动的距离。“斑马线”元素(由蓝色箭头表示)移动了最多,移动了约视口高度的 30%。因此,在此示例中,距离分数为
0.3
- CLS为
0.60 x 0.3 = 0.18
结语
作为系列的开篇,本文分享了对前端性能优化的目标和常见性能指标,也对Google研究出的核心性能指标做了介绍。
后面会基于如何优化核心性能指标进行更细节的分享,希望能写出更好的博客,与各位共勉~