文章目录
为什么要有前端监控?
许多体验问题(页面加载慢、页面白屏、操作卡顿或无响应、请求响应慢、请求频繁报错、排版样式错乱)等单靠用户反馈并不现实。
前端监控的好处:
- 提升稳定性,更快地发现异常、定位异常、解决异常:JS 错误、接口异常、资源异常、白屏……
- 提升用户体验,建立性能规范,长期关注优化:页面性能、接口性能、资源加载性能、卡顿监控
- 了解业务数据,指导产品升级:PV && UV、业务数据、行为监控
前端监控的流程:
- 数据采集
- 组装上报
- 清洗存储
- 数据消费
1. 数据采集
2. 组装上报
3. 清洗存储
4. 数据消费
指标
一、常用性能标准
- Navigation Timing:提供了文档导航过程中完整的计时信息,即一个文档从发起请求到加载完毕各阶段的性能耗时。
- Performance Timeline:提供了获取各种类型(navigation、resource、paint 等)的性能时间线的方法。
- Resource Timing:提供文档中资源的计时信息。
- Paint Timing:记录在页面加载期间的一些关键时间点。
- Long Tasks API:检测长任务的存在,长任务会在很长一段时间内独占UI线程,并阻止其他关键任务的执行——例如响应用户输入。
二、传统性能指标
传统的性能指标主要依赖 Navigation Timing 以及 Navigation Timing 2,通过记录一个文档从发起请求到加载完毕的各阶段的性能耗时,以加载速度来衡量性能。
- 初始化阶段
- navigationStart:用户完成卸载前一个文档的时间点
- redirectStart:页面重定向的开始时间,或者是0。
- redirectEnd:页面重定向的结束时间,或者是0。
- 请求阶段:
- fetchStart:浏览器发起资源请求时,有缓存时,则返回读取缓存的开始时间。
- domainLookupStart:查询DNS的开始时间。
- domainLookupEnd:查询DNS的结束时间。
- connectStart:浏览器开始与服务器连接时的时间。
- secureConnectionStart:如果页面使用 HTTPS,它的值是安全连接握手之前的时刻。
- connectEnd:当浏览器端完成与服务器端建立连接的时刻。
- responseStart:指 客户端收到从服务器端(或缓存、本地资源)响应回的第一个字节的数据的时刻。
- responseEnd:指客户端收到从服务器端(或缓存、本地资源)响应回的最后一个字节的数据的时刻。
- 解析渲染阶段:
- domLoading:浏览器即将开始解析第一批收到的 HTML 文档字节,
Document.readyState
变为loading
。 - domInteractive:当前网页 DOM 结构结束解析、开始加载内嵌资源的时间点。
Document.readyState
变为interactive
。 - domContentLoadedEventStart: 当解析器发送 DomContentLoaded 事件,所有需求被执行的脚本已经被解析。
- domContentLoadedEventEnd:所有需要立即执行的脚本已经被执行。
- domComplete:当前文档解析完成,
Document.readyState
变为complete
。 - loadEventStart:作为每个网页加载的最后一步,浏览器会出发 load 事件,以便触发额外的应用逻辑。如果这个事件还未被发送,它的值将会是0.
- loadEventEnd:load 事件执行完成。如果这个事件还未被发送,或者尚未完成,它的值将会是0。
- domLoading:浏览器即将开始解析第一批收到的 HTML 文档字节,
各阶段耗时计算:
- Redirect 重定向: r e d i r e c t E n d − r e d i r e c t S t a r t redirectEnd - redirectStart redirectEnd−redirectStart
- App cache缓存: d o m a i n L o o k u p S t a r t − f e t c h S t a r t domainLookupStart - fetchStart domainLookupStart−fetchStart
- DNS 解析: d o m a i n L o o k u p E n d − d o m a i n L o o k u p S t a r t D N S domainLookupEnd - domainLookupStart DNS domainLookupEnd−domainLookupStartDNS
- TCP TCP 连接: c o n n e c t E n d − c o n n e c t S t a r t connectEnd - connectStart connectEnd−connectStart
- SSL SSL 握手: c o n n e c t E n d − s e c u r e C o n n e c t i o n S t a r t connectEnd - secureConnectionStart connectEnd−secureConnectionStart
- Request 请求耗时: r e s p o n s e S t a r t − r e q u e s t S t a r t responseStart - requestStart responseStart−requestStart
- Response 响应耗时: r e s p o n s e E n d − r e s p o n s e S t a r t responseEnd - responseStart responseEnd−responseStart
- Processing: d o m C o m p l e t e − d o m L o a d i n g domComplete - domLoading domComplete−domLoading
实际运用中的常见指标
- Load 页面完全加载耗时: l o a d E v e n t E n d − n a v i g a t i o n S t a r t loadEventEnd - navigationStart loadEventEnd−navigationStart
- DOMReady: d o m C o n t e n t L o a d e d − f e t c h S t a r t domContentLoaded - fetchStart domContentLoaded−fetchStart
- DOMParse: d o m I n t e r a c t i v e − r e s p o n s e E n d domInteractive - responseEnd domInteractive−responseEnd
- TTFB: r e s p o n s e S t a r t − n a v i g a t i o n S t a r t responseStart - navigationStart responseStart−navigationStart
Time To First Byte 是发出页面请求到接受到应答数据第一个字节的时间综合,它包含了 DNS 解析时间、TCP 连接时间、发送 HTTP 请求时间和获得响应消息第一个字节的时间
- ResourceLoad 剩余资源加载耗时: d o m C o m p l e t e − d o m C o n t e n t L o a d e d domComplete - domContentLoaded domComplete−domContentLoaded
如何采集
三、以用户为中心的指标
传统性能指标在乎细节实现,以用户为中心的指标在乎用户体验。
从用户体验对指标进行分类:
用户体验 | 指标 |
---|---|
发生了吗? | FP(First Paint), FCP(First Contentful Paint) |
内容有用吗? | FMP(First Meaningful Paint), SI(Speed Index) |
内容可用吗? | TTI(Time to Interactive) |
令人愉悦吗? | FID(First Input Delay) |
1. 发生了吗?FP && FCP
来自 Paint Timing 标准,记录在页面加载期间的一些关键时间点。
- FP (First Paint):首次渲染的时间点(可以渲染任意东西),FP 时间点之前,用户看到的都是没有任何内容的白色屏幕。
- FCP(First Contentful Paint): 首次渲染有内容的时间点(文本或者图像),FCP 时间点之前,用户看到的都是没有任何实际内容的屏幕。
FCP 反映当前 Web 页面的网络加载性能情况、页面 DOM 结构复杂度等情况、Inline script 的执行效率的情况。当所有的阶段性能做的非常好的情况下,FCP 会越短,用户等待时间越短,流失概率越低。
2. 内容有用吗?FMP & SI
FMP(First Meaningful Paint):首次绘制有意义内容速度时间点。
FMP 通常被认为是用户获取到了页面主要信息的时刻,也就是说此时用户的需求是得到了满足的,所以产品通常也会关注 FMP 指标。
前端业界现在比较认可的一个计算 FMP 的方式就是「页面在加载和渲染过程中最大布局变动之后的那个绘制时间点即为当前页面的 FMP」
FMP 代码实现原理:
理论依据:认为「DOM结构变化的时间点|与之对应「渲染的时间点」近似相同,所有 FMP 的时间点为「DOM 结构变化最剧烈的时间点」,「DOM 结构变化的时间点」可以利用 MutationObserver API 来获得。
- 通过 MutationObserver 监听每一次页面整体的 DOM 变化,触发 MutationObserver 的回调。
- 再通过回调计算出当前 DOM 数的分数,分数变化最剧烈的时刻,即为 FMP 的时间点。
SI(Speed Index):衡量页面可视区域加载速度,帮助检测页面的加载体验差异。
A 和 B 的首次内容出现和完全加载时间是一样的,但是从用户角度 A 的体验明显更好。
3. 内容可用吗?
TTI(Time to Interactive):测量页面从开始加载到主要子资源完成渲染,并能够快速、可靠地响应用户输入所需的时间。
TTI 算法实现
- 首先进行首次内容绘制 FCP。
- 沿时间轴正向搜索时长至少为 5 秒的安静窗口,其中,安静窗口的定义为:没有长任务且不超过两个正在处理的 GET 网络请求。
- 沿时间轴反向搜索安静窗口之前的最后一个长任务,如果没有找到长任务,则在 FCP 步骤停止执行。
- TTI 是安静窗口之前最后一个长任务的结束时间(如果没有找到长任务,则与 FCP 值相同)。
4. 令人愉悦吗?FID
源自 Event timing 标准,深入了解由用户交互触发的事件的延迟。
通常情况下,Input Delay 是因为浏览器主线程在忙于执行其他操作,无暇处理用户的交互操作。
FID(First Input Delay):测量从用户第一次与页面交互(比如点击链接、点击按钮等等)直到浏览器对交互做出响应,实际能够开始处理事件所经过的时间。
- FID 反映用户对页面交互性和响应性的第一印象,良好的第一印象有助于用户建立对整个应用的良好印象。
- 页面加载资源,资源的处理任务最重,也最容易产生输入延迟,因此关注 FID 指标对于提升页面的可交互性有很大收益。
- FID 和页面加载完成后的 Input Delay 具有不同的解决方案。针对 FID,我们一般建议通过 Code Splitting 等方式减少页面加载阶段 JS 的加载、解析和执行时间。而页面加载完成后的 Input Delay,通常是由于开发人员代码编写不当、引起 JS 执行时间过长而产生的。
总结
业界持续研究和开发用来描述良好用户体验的关键指标。随着对于用户体验的理解的深入和测量能力的增强,指标也同样需要随之进化。
这个过程的结果是三个全新的性能指标,它们填补了用户体验故事的空白,分别是:
- LCP(Largest Contentful Paint)
- TBT(Total Blocking Time)
- CLS(Cumulative Layout Shift)
5. LCP
LCP(Largest Contentful Paint):最大的内容在可是区域内变得可见的时间点。
最大的元素,例如一篇文章中的一大段文字或产品页面上的一张图片,大概就是让你理解页面内容的最有用的元素。
为什么我们需要 LCP?
指标 | 定义 | 存在的问题 |
---|---|---|
FCP | 首次内容绘制时间 | 通常与用户无关 |
FMP | 首次绘制有意义内容的时间点 | 非标准化并且难以在浏览器之间统一实现,约 20% 的情况下不准确。 |
SI | 跟踪在饰扣中加载内容的视觉进程 | 复杂的指标,难以解释。计算密集,不可用于线上监控。 |
LCP 则不同:
- 容易理解
- 给出与 FMP 相似的结果
- 容易计算和上报
6. TBT
TBT(Total Blocking Time):量化主线程在空闲之前的繁忙程度,有助于理解在加载期间,页面无法响应用户输入的时间又多长。
长任务:指在主线程上运行超过 50 毫秒的任务,超过 50ms 后的任务超时,都算作任务的阻塞时间。
一个页面的 TBT,是从 FCP 到 TTI 之间所有长任务的阻塞事件的总和。
TTI 有时可能会误导用户,但当与 TBT 结合使用时,你就会清楚地了解页面对用户输入的响应程度。
7. CLS
CLS(Cumulative Layout Shift):量化了在页面加载期间,视口中元素的移动程度。
当我们点击按钮时,突然出现了一块内容,无论是以一种增加意外点击几率的方式加载广告,还是在加载图片时文本向下移动,内容的意外移动都会让人非常不舒服。
CLS 通过测量偏移度,来帮助你解决这个问题,它引入了用户体验中一个全新的类别——可预测性。CLS 分数越低越好,因为这意味着在整个页面交互过程中发生的内容的偏移较少。
单次布局偏移的计算公式:
s c o r e = 距离系数 × 影响分数 score = 距离系数 \times 影响分数 score=距离系数×影响分数比如:
元素向下移动了视口高度的 1 3 \frac{1}{3} 31,所以距离系数是 0.33。
元素在其起始位置和移动后的位置所占的面积占视口总面积的 2 3 \frac{2}{3} 32,因此影响分数是 0.66,布局偏移得分为 0.33 × 0.66 = 0.2178 0.33 \times 0.66 = 0.2178 0.33×0.66=0.2178。
关于 CLS 的计算细节和原理可以查看 Cumulative Layout Shift (CLS)。
以用户为中心的性能指标
用户体验 | 指标 |
---|---|
发生了吗? | FP(First Paint), FCP(First Contentful Paint) |
内容有用吗? | FMP(First Meaningful Paint), SI(Speed Index), LCP(Largest Contentful Paint) |
内容可用吗? | TTI(Time to Interactive), TBT(Total Blocking Time) |
令人愉悦吗? | FID(First Input Delay), CLS(Cumulative Layout Shift) |
四、根据性能衡量站点满意度
1. 定义指标阈值
没有一个完美的阈值,并且我们有时可能需要从多个合理的候选阈值中进行选择。我们不会想弄清“完美的阈值”是多少,相反地,我们专注于认清“哪一个候选阈值最符合我们的标准”。
通常选择样本量的第 75 个百分位数来设置阈值,基于一下两个标准:
- 确保对页面或网站的大多数访问都达到了目标性能水平。
- 不受到异常值的过度影响。
2. 关键指标的基准线
Metric Name | Goods(ms) | Needs Improvement(ms) | Poor(ms) |
---|---|---|---|
FP(First Paint) | 0-1000 | 1000-2500 | Over 2500 |
FCP(First Contentful Paint | 0-1800 | 1800-3000 | Over 3000 |
LCP(Largest Contentful Paint | 0-2500 | 2500-4000 | Over 4000 |
TTI(Time to Interactive | 0-3800 | 3800-7300 | Over 7300 |
FID(First Input Delay) | 0-100 | 100-300 | Over 300 |
CLS(Cumulative Layout Shift) | 0-0.1(无单位) | 0.1-0.25(无单位) | Over 0.25(无单位) |
这里为什么没有 FMP、TBT 和 SI 呢?
经过测试,LCP 非常近似于 FMP 的时间点,FMP 渐渐可以通过 LCP 代替。
SI 的计算逻辑比较复杂,更常用在 Lighthouse 中,而非线上监控。
虽然 TBT 可以在线上进行测量,但不建议这么做,因为用户交互会影响网页的 TBT,从而导致报告中出现大量的差异,线上监控推荐使用 FID。
Chrome 中的 DevTools 已经集成 LightHouse,可以打开 DevTools 直接使用:
五、获取站点的性能指标
1. 通过代码或者插件获得
web-vitals 相关指标可以使用 npm 包 或者 chrome 插件获取。
2. 本地查看:Devtools 查看或者使用 lighthouse
Reference
[1] https://web.dev/user-centric-performance-metrics/
[2] https://calibreapp.com/blog/new-generation-of-performance-metrics
[3] https://web.dev/navigation-and-resource-timing/
[4] https://web.dev/i18n/zh/rail/
[5] https://web.dev/defining-core-web-vitals-thresholds/
[6] https://chromium.googlesource.com/chromium/src/+/master/docs/speed/metrics_changelog/README.md
[7] https://web.dev/performance-scoring/
[8] https://blog.chromium.org/2020/05/the-science-behind-web-vitals.html
前端性能优化
一、优化传统性能指标
优化思路:
ROI: Ruturn on Investment,投资回报率
1. 网络优化
- 开启 HTTP/2
关注兼容性问题,同时做好域名收敛
- 开启 brotli 压缩
相比于 gzip,它具有更高的压缩比和更快的压缩性能
- 善用 HTTPS
通过有效的优化手段,比如 Session Resume,OCSP Stapling 等等,提升 HTTPS 性能
- 使用 CDN 部署静态资源
有效降低访问延迟,提高可用性
- DNS 预解析
常用于 CDN 域名场景,减少 DNS 耗时
- 提前建立网络连接
常用于 Server API 等域名,兼容性更好
2. 缓存优化
3. 资源加载优化
- 优化 HTML 文件
- 控制体积在 30kb 以内
- 优化 DOM 节点
- 压缩
- 谨慎使用内联
- ……
- 优化 JS 文件
- 请求时机:defer、async、动态加载
- 文件体积:常规的压缩、Tree Shaking、按需加载、精准控制 Polyfill……
- 加载方式:减少网络请求、充分利用缓存……
- 优化 CSS 文件、字体文件、图片文件
- 请求时机 :关键的先请求,次要的后请求
- 文件体积:如何才能让资源的体积更小?
- 加载方式:减少请求数、善用缓存……
二、优化以用户为中心的关键指标
优化思路:不同指标,计算方式不同、关注的依赖项不同,了解请求指标的依赖项,着重优化指标的相关依赖项。
1. 优化 FP & FCP
尽快渲染,加载快、解析快、渲染快,最终的值才会越优秀。
- 消除阻塞渲染的资源
- 缩小 CSS && 移除未使用的 CSS
- 预连接到所需的来源
- 减少服务器响应时间 (TTFB)
- 避免多个页面重定向
- 预加载关键请求
- 避免巨大的网络负载
- 使用高效的缓存策略服务静态资产
- 避免 DOM 过大
- 最小化关键请求深度
- 确保文本在网页字体加载期间保持可见
- 保持较低的请求数和较小的传输大小
2. 优化 FMP & LCP
缩短页面关键路径的渲染时间
主要受四个因素的影响:
- 缓慢的服务器响应速度 ➡️ 网络优化:HTTP/2、CDN、DNS 预解析、提前建立网络连接……
- JS 和 CSS 渲染阻塞 ➡️ 削减 CSS、延迟加载非关键 CSS、内联关键 CSS、削减压缩 JS 文件、延迟加载未使用的 JS 文件、最大限度减少未使用的 Polyfill……
- 资源加载时间 ➡️ 优化和压缩图片、预加载重要资源、压缩文本文件、自适应服务……
影响 LCP 的元素类型为:
<img
元素、内嵌在<svg>
元素内的<image>
元素、<video>
元素(使用封面图像测量 LCP)、通过url()
函数(而非使用 CSS 渐变)加载的带有背景图像的元素、包含文本节点或其他行内级文本元素的块级元素。
- 客户端渲染 ➡️ 最小化关键 JS、使用服务端渲染、预渲染……
3. 优化 FID
如何更快地响应用户交互
- 分割长任务
- 优化页面,尽快做好交互准备
- 移除关键路径上非必要组件加载的脚本;
- 尽最大限度地减少需要在客户端进行后的数据量;
- 按需加载第三方代码;
- 按先加载可以为用户提供最大价值的内容;
- 使用 Web Worker
- 减少 JS 执行时间
4. 优化 CLS
尽量减少布局偏移
CLS 较差的常见原因:
- 无尺寸的图像 ➡️ 设置长宽、或者使用 CSS 宽比容器预留所需的空间
- 无尺寸的广告、嵌入和 iframe ➡️ 预留空间、避免在可视区域顶部放置广告、使用占位符或者预先计算足够的空间
- 动态注入的内容 ➡️ 预留空间,比如使用占位符或者骨架屏等
- 导致不可见文本闪烁(FOIT)、无样式文本闪烁(FOUT)的网络字体 ➡️ 预加载字体
- 在更新 DOM 之前等待网络响应的操作 ➡️ 倾向于选择 transform 动画,而不是触发布局偏移的属性动画(CSS 触发器和高性能动画)
5. 优化 TTI
尽快的渲染、尽早的请求、请求尽快结束、尽量避免长任务
- 参考如何优化 FCP
- 预加载关键请求
- 最小化关键请求深度
- 减少 JS 执行时间
- 最小化主线程工作
- 保持较低的请求数和传输大小
三、案例
- www.tiktok.com 开启 br 压缩,html 体积减少约 10%
- 番茄小说频道页通过压缩图像、延迟加载首屏无用 JS、精简 JS 和 CSS 等方式,将 FCP 降低了 20%
- 飞书绩效通过减小 JS 文件体积、按需加载、缓存优化等方式,将 LCP 降低了 35%
- TikTok PC 热点页通过移除首屏非必须的区号选择列表,将 FID 指标降低了 30%。
Reference
[1] https://web.dev/fast/
[2] https://web.dev/i18n/zh/rail/
[3] https://developer.mozilla.org/zh-CN/docs/Web/Performance
[4] https://web.dev/fcp/
[5] https://web.dev/lcp/
[6] https://web.dev/optimize-lcp/
[7] https://web.dev/optimize-cls/
[8] https://web.dev/optimize-fid/
[9] https://web.dev/tti/
Resource
- 火山引擎:https://console.volcengine.com/apmplus/console/overview
- 推文链接:https://mp.weixin.qq.com/s/DpOYfw2bVCXNlrPTrD3mdA
- PPT: https://aozev637mr.feishu.cn/drive/folder/fldcnNi92sJHp8DUAGLlDbnd7uf
- Video:
https://space.bilibili.com/99642456?spm_id_from=333.337.0.0