谈谈web前端性能指标

383 阅读6分钟

前言

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 paintSpeed 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)

最大内容绘制,该指标用于衡量从用户打开页面->视口内可见的最大内容元素的渲染时间。对于用户来说,已经看到了页面的主要内容。我们可以通过图片对比一下两个指标的差别。

https://yppphoto.hellobixin.com/yppphoto/23bcae3c504e46beb658e77b6cbe87e6.jpg

FCP&LCP对比

LCP会实时计算,页面中最大内容的渲染时间,直到用户发生交互,上报最大模块加载时间。而FCP是在加载出内容后直接上报,如果页面有初始化loading态、骨架屏、异步渲染视图等,LCP是相对比较准确的指标。在比如活动页,最大也最重要的模块一般是kv,FCP是很难准确计算kv加载完成时间的。因为上报机制的原因,该指标也有丢失的风险。

FID(First Input Delay)

首次输入延迟,也叫做用户第一印象,该用于衡量用户第一次与页面交互–>页面做出响应的延迟时间。 用户看到页面后进行交互,发现没响应,为什么呢?因为你还在跑js代码、因为你还在请求接口、因为你还在渲染页面。该指标就是记录无响应的延迟时长,造成用户的卡顿时间越长,用户的印象自然就越差。

CLS(Cumulative Layout Shift)

累计布局偏移,也叫做视觉稳定性。或许你也有过类似的体验:当你阅读文字时,文字突然滚动到了下面。页面的内容经常被莫名其妙的滚动,这时候就用到了该项指标。它会计算本次偏移影响的视口占比本次偏移距离占比。两个占比相乘,就是该项指标。


本次偏移影响的视口占比

https://yppphoto.hellobixin.com/yppphoto/5abace2a92684c4abe57a81c1511c790.jpg

本次偏移距离占比

https://yppphoto.hellobixin.com/yppphoto/b6905a09fe81431c8fd289786a9018b8.jpg


统一获取方式:

// 下载
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等。如下图所示:

https://yppphoto.hellobixin.com/yppphoto/80d48372644746a591119528fac201a0.png

页面加载图

这些指标会内置在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’)数据

https://yppphoto.hellobixin.com/yppphoto/120a211833754399af0a123222cd516a.png

timing数据

https://yppphoto.hellobixin.com/yppphoto/94886faedcf2424fa795823bf005999a.png


资源加载性能

页面每个阶段的数据有了,剩下最主要的数据就是资源的加载了,一个页面最主要的资源有js,css,img,mp4等等。我们可以监听这些文件的加载时间,大小等数据,如果用户体验数据不太好,或许可以在这些文件的加载过程上找到原因。

获取方式:

const resource = window.performance.getEntriesByType('resource')
console.log(resource)

https://yppphoto.hellobixin.com/yppphoto/c4821641836847c1b23e799fc3900642.png

尾声

关于web页面性能指标,到这里就告一段落了,后续我会继续更新,感谢读者的点赞,您的支持就是我最大的动力。