前言
Google DoubleClick 研究表明:如果一个移动端页面加载时长超过 3 秒,用户就会放弃而离开。BBC 发现网页加载时长每增加 1 秒,用户就会流失 10%。
2025年的今天,随着硬件设备的不断升级,vue、react等虚拟dom框架的推广,webpack、rollup等优质的打包工具的使用,性能问题似乎已经不是一个问题。就拿我们内部写的h5页面来说,随便打开一个页面,感觉都很快,根本用不了3秒。
但是话又说回来了,这真的能代表我们的页面性能吗?如果页面都这么快,我们还需要性能监控吗?要知道,一个页面打开的速度会受到很多因素的影响。一万个用户每人打开一次页面,就有一万次性能数据,每次的页面性能都是不一样的。你快可能是因为:
- 有本地缓存
- 使用的是局域网
- 网络是5G
- 设备是最新的电脑或手机
- …
难道用户都是这样的条件吗?所以说,性能监控依旧是web开发不可或缺的一部分。而在性能监控之前,最主要的事情就是上报正确的指标,本篇文章我们就聊聊性能指标那些事儿。
正文
前端性能数据的标准有很多,有google开发者最早提出的RAIL模型,有2020最新发布的Chrome 83中新增的Core Web Vitals标准,还有性能检测工具lighthouse提出的First meaningful paint、Speed Index等等指标。那到底那些指标是我们应该上报的数据呢?
我认为可以大致分为用户体验数据和页面加载数据两大部分,用户体验数据用来体现用户的真实感受,比如真正看到画面的时间,操作页面时的卡顿情况等;页面加载数据用来还原项目的整个加载过程,辅助后续分析优化项目。下面我们就来聊聊这些指标的含义和获取方式。
白屏和首次内容绘制
FP(First Paint)
白屏时间,这也是大家经常提到的指标。该指标用于衡量从用户打开页面->页面开始有东西呈现的时间。这个过程包括dns查询、建立TCP连接、发送首个http请求(如果使用https还要介入TLS的验证时间)、返回html文档、html文档head解析完毕。这个时间或许页面还没有呈现内容,但是已经显示了背景颜色,对用户来说已经不是白屏了。
获取方式:
const paintArr = window.performance.getEntriesByType('paint')
const FP = paintArr.find(v=>v.name==='first-paint')
console.log('FP耗时:',FP.startTime)
FCP(First Contentful Paint)
首次内容绘制,该指标用于衡量从用户打开页面->用户首次在页面上看到内容的时间,内容包括:文本、图片、视频、SVG、canvas等。相对于FP,该指标可以更直观的让用户感知。这个时间是页面真正显示内容的时间,对于用户来说,已经看到了内容,或文字,或图片信息。
获取方式:
const paintArr = window.performance.getEntriesByType('paint')
const FCP = paintArr.find(v=>v.name==='first-contentful-paint')
console.log('FCP耗时:',FCP.startTime)
Core Web Vitals指标
为了更准确的还原用户体验,2020年随着Chrome 83的发布,google又提出了Core Web Vitals,其中提到了用户体验的三个方面:加载、交互性和视觉稳定性。由此作为web健康指标的基础。而这三大方面对应的指标就是LCP、FID、CLS。
LCP(Largest Contentful Paint)
最大内容绘制,该指标用于衡量从用户打开页面->视口内可见的最大内容元素的渲染时间。对于用户来说,已经看到了页面的主要内容。我们可以通过图片对比一下两个指标的差别。
FCP&LCP对比
LCP会实时计算,页面中最大内容的渲染时间,直到用户发生交互,上报最大模块加载时间。而FCP是在加载出内容后直接上报,如果页面有初始化loading态、骨架屏、异步渲染视图等,LCP是相对比较准确的指标。在比如活动页,最大也最重要的模块一般是kv,FCP是很难准确计算kv加载完成时间的。因为上报机制的原因,该指标也有丢失的风险。
FID(First Input Delay)
首次输入延迟,也叫做用户第一印象,该用于衡量用户第一次与页面交互–>页面做出响应的延迟时间。 用户看到页面后进行交互,发现没响应,为什么呢?因为你还在跑js代码、因为你还在请求接口、因为你还在渲染页面。该指标就是记录无响应的延迟时长,造成用户的卡顿时间越长,用户的印象自然就越差。
CLS(Cumulative Layout Shift)
累计布局偏移,也叫做视觉稳定性。或许你也有过类似的体验:当你阅读文字时,文字突然滚动到了下面。页面的内容经常被莫名其妙的滚动,这时候就用到了该项指标。它会计算本次偏移影响的视口占比和本次偏移距离占比。两个占比相乘,就是该项指标。
本次偏移影响的视口占比
本次偏移距离占比
统一获取方式:
// 下载
npm install web-vitals
// 使用
import { getLCP, getCLS, getFID } form 'web-vitals'
getLCP(console) // LCP
getCLS(console) // CLS
getFID(console) // FID
页面加载流程数据
我们不仅要关注用户体验数据,也要关注页面渲染的整个过程。web页面从输入地址直到加载完成并显示内容,其实做了很多工作。其中包含了重定向、读取缓存、DNS查询、TCP链接、请求资源、响应请求、dom加载渲染、页面load等。如下图所示:
页面加载图
这些指标会内置在window.Performance中,也是我们页面指标的重要组成部分。根据页面加载阶段,可以聚合成以下几个阶段指标:
- 重定向耗时
- 读取缓存耗时
- DNS查询耗时
- TCP连接耗时
- 请求耗时
- 响应耗时
- 初始化DOM耗时
- 解析DOM耗时
- 执行onLoad耗时
获取方式:
// 通过getEntriesByType获取
const navigationData = window.performance.getEntriesByType('navigation')[0]
console.log('加载过程用时数据:',navigationData)
// getEntriesByType获取到的数据是以页面加载开始时间为初始点的增量数据。如果想要获取时间戳,可以用timeOriginconst
origin = window.performance.timeOriginconst
connectEnd = origin + navigationData.connectEnd
console.log('connectEnd时间戳:',connectEnd)
// 通过timing,timing是已经被废弃的API,但是兼容性最好,可以用于兜底处理。
const timing = window.performance.timing
console.log('加载过程各个阶段的时间戳:',timing)
getEntriesByType(‘navigation’)数据
timing数据
资源加载性能
页面每个阶段的数据有了,剩下最主要的数据就是资源的加载了,一个页面最主要的资源有js,css,img,mp4等等。我们可以监听这些文件的加载时间,大小等数据,如果用户体验数据不太好,或许可以在这些文件的加载过程上找到原因。
获取方式:
const resource = window.performance.getEntriesByType('resource')
console.log(resource)
尾声
关于web页面性能指标,到这里就告一段落了,后续我会继续更新,感谢读者的点赞,您的支持就是我最大的动力。