前端项目优化-4.性能指标和工具

性能指标有哪些

  • 加载时间相关指标‌:
    • FP(First Paint):页面第一次绘制像素的时间。
    • FCP:首次内容绘制 控制在 1.8s 以内,页面从开始加载到页面内容的任何部分在屏幕上完成渲染的时间,是测量加载速度感知的重要指标之一。
    • LCP:最大内容绘制 <= 2.5s 合格,是指根据页面首次开始加载的时间点来报告可视区域内可见的最大图像或者文本块完成渲染的相对时间
    • TTI(Time to Interactive):页面变得完全可交互的时间点‌,即页面已呈现,可以响应用户输入。
  • 用户交互相关指标‌:
    • FID(First Input Delay):用户第一次与页面交互到浏览器实际响应的时间‌,反映了页面的响应速度12。
    • INP(Interaction to Next Paint):衡量页面对用户交互的整体响应能力‌,取代了FID。
    • CLS:累计布局偏移(CLS)是测量视觉稳定性的重要指标。是整个页面声明周期内发生的所有意外布局偏移中最大一连串的布局偏移分数。
      页面内容的意外偏移大多是由于异步资源加载,或者动态添加 DOM 元素到页面现有内容上方导致的。罪魁祸首可能是未知尺寸的图像或视频、实际渲染后比后备字体更大或更小的字体等。
  • 资源加载相关指标‌:
    • DNS 解析时间:将域名解析为 IP 地址的时间。
    • TCP 连接时间:建立 TCP 连接的时间。
    • SSL 握手时间:完成 SSL 握手的时间(如果使用 HTTPS)。
    • TTFB(Time to First Byte):从请求发出到收到第一个字节的时间,反映服务器响应速度。
    • 资源下载时间:下载各种资源(HTML、CSS、JavaScript、图片等)的时间。
  • 其他指标‌:
    • 白屏时间:用户看到空白页面的时间。

    • SI(Speed Index):页面内容从开始加载到完全呈现所需的时间。
      • 减少主线程工作
      • 减少 JavaScript 执行时间

    • TBT:总阻塞时间,是页面被阻塞响应用户交互的总时间。 TBT = LCP (首次最大内容绘制)和可交互时间之间所有长时间任务的阻塞部分之和。是测量页面加载响应的重要指标。超过 50 毫秒的任务即为长任务,超出 50 毫秒的时间量为阻塞部分

分析工具

NetWork

network面板,反应了请求资源 size时长数量接口响应时长发起数量响应状态 、报文size等;

  • 侧重点在于分析网路链路的情况,主要关注响应时间和请求数量。
  • 瀑布图 每一行都是一次单独的浏览器请求.
  • 这个图越长, 说明加载网页过程中所发的请求越多.
  • 每一行的宽度, 代表浏览器发出请求并下载该资源的过程中所耗费的时间.

构建打包分析工具 webpack-bundle-analyzer

项目构建后生成的bundle包是压缩后的,排查出一些无用的模块,过大的模块
bundle包被解析的一览无余。其中模块面积占的越大说明在bundle包中size越大。

  • 显示包中所有打入的模块
  • 显示模块 sizegzip后的size
    使用 先install安装 构建包完毕后会自动弹出一个窗口展示上图信息。
1
2
3
4
5
6
7
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
plugins: [
new BundleAnalyzerPlugin()
]
}

借助 Chrome DevTools: lighthouse, performance 进行性能分析

  1. 打开 Chrome DevTools,选择 lighthouse / Performance 选项卡。
  2. 点击“Start”按钮开始性能测量。
  3. 进行页面操作,触发需要测量的性能指标。
  4. 点击“Stop”按钮结束性能测量。

火焰图推荐阅读:
可观测性之巧用 “ 火焰图 ” 快速分析链路性能

在线性能测试工具

  • Pingdom
  • Load Impact
  • WebPage Test
  • Octa Gate Site Timer
  • Free Speed Test
  • Google Analytics
  • WebPageTest

借助 performance API 进行封装上报

狠狠地研究了下 PerformanceObserver API
使用 Performance API 获取页面性能

Performance 主接口在 Window 和 Worker 全局作用域下都可用,并允许你增加自定义性能条目、清除性能条目,以及查询性能条目。通过 封装并上报三方数据平台(如,神策),进行监控。
一般 常用两种 window.performancePerformanceObserver

  • window.performance: 获取页面加载的性能数据或测量代码执行时间。
  • PerformanceObserver: 实时监听性能事件(如页面渲染时间、用户交互延迟等)。

两者结合使用可以更全面地监控和优化页面性能。

window.performance 最简单的使用

window.performance.getEntries() 封装并上报,不需要任何参数,返回当前 Performance Timeline 上的所有条目。
返回的是一个 PerformanceEntry 对象的列表,每个对象都包含了一个性能条目的详细信息。
支持 window.performance 的浏览器环境中,可以方便地使用性能测量功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 获取性能数据
const performanceData = window.performance.getEntries()[0];

// 计算关键性能指标
const metrics = {
// DNS解析时间
dnsTime: performanceData.domainLookupEnd - performanceData.domainLookupStart,
// TCP连接时间
tcpTime: performanceData.connectEnd - performanceData.connectStart,
// 首字节时间
ttfb: performanceData.responseStart - performanceData.navigationStart,
// DOM加载时间
domLoadTime: performanceData.domContentLoadedEventEnd - performanceData.navigationStart,
// 页面完全加载时间
loadTime: performanceData.loadEventEnd - performanceData.navigationStart
};

// 转换为JSON字符串用于上报
const metricsString = JSON.stringify(metrics);
  1. DNS解析时间: domainLookupEnd - domainLookupStart
  2. TCP建立连接时间: connectEnd - connectStart
  3. 白屏时间: responseStart - navigationStart
  4. dom渲染完成时间: domContentLoadedEventEnd - navigationStart
  5. 页面onload时间: loadEventEnd - navigationStart

Performance Observer

LCP

指视图中最大图像和文本块呈现的时间

1
2
3
4
5
6
7
8
9
10
11
/*******   关键指标   ******/
// FCP 一般来说,LCP数据会取最后一个找到的内容作为结果
const observer = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
console.log(entry)
});
});
observer.observe({
type: "paint",
buffered: true
});

loadingTime 为 最终 LCP 值,其余参数 解析:

  • element: 当前最大的内容绘制元素
  • loadingTime: 加载时间
  • renderTime: 渲染时间。如果是跨域请求,则为0。
  • size: 元素本身的面积
  • startTime: 如果 renderTime 不为0,则返回 renderTime;否则返回 loadingTime
FCP

指的是任何内容的一部分首次在屏幕上呈现的时间。

1
2
3
4
5
6
7
8
9
10
11
/*******   关键指标   ******/
// FCP 与之类似的还有一个指标是 FP(First Paint) ,表示第一个像素绘制到屏幕上的时间。”
const observer = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
console.log(entry)
});
});
observer.observe({
type: "paint",
buffered: true
});

startTime 为 最终 FCP 值,其余参数 解析:

  • duration: 持续时间,这里是0。
  • startTime: 返回绘制发生时的时间戳。
FID

指的是用户首次与页面交互到浏览器实际能够开始处理程序以响应该交互的时间

1
2
3
4
5
6
7
8
9
10
11
12
13
/*******   关键指标   ******/
// FID指的是用户首次与页面交互到浏览器实际能够开始处理程序以响应该交互的时间
// 缩放和滚动以及持续性事件(如mousemove、pointermove、touchmove、wheel和drag)不包括在这个指标中
const observer = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
const FID = entry.processingStart - entry.startTime;
console.log(entry)
});
});
observer.observe({
type: "first-input",
buffered: true
});

processingEnd - processingStart 为 最终 FID 值,其余参数 解析:

  • duration: 表示从 startTime 到下一个渲染绘制的时间。
  • processingStart: 测量用户操作与事件处理程序开始运行之间的时间。
  • processingEnd: 测量事件处理程序运行所花费的时间。
  • target: 返回关联事件的 DOM。
INP

指标通过观察用户在页面生命周期内发生的所有点击、触摸和键盘交互的延迟来评估页面对用户交互的整体响应能力。最终的 INP 值是观察到的最长交互,忽略异常值。INP 将于2024年3月12日取代 FID,成为核心 Web Vitals 指标。

NIP 仅会受到以下事件的影响:

  • 用鼠标点击
  • 点击带有触摸屏的设备
  • 按下物理键盘或屏幕键盘上的某个键

与 FID 的关系:

  • INP 考虑了所有页面交互,而 FID 仅考虑第一次交互。
  • INP 不仅仅关注于首次交互,而是通过对所有交互进行抽样,以全面评估响应能力,使 INP 成为比 FID 更可靠的整体响应能力指标。
  • 由于 Performance API 中没有提供 INP 的响应能力,因此这里不提供具体示例。 只能通过三方工具获取。
CLS

衡量页面在其整个生命周期内发生的最大意外布局偏移分数
在此评估中,仅考虑元素改变其初始位置的情况,对于增加新元素到DOM或元素的宽度、高度改变等情况不予以计算。

1
2
3
4
5
6
7
8
9
10
// cls
const observer = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
console.log(entry)
});
});
observer.observe({
type: "layout-shift",
buffered: true
});

valuet 为 最终 CLS 值,其余参数 解析:

  • value: 返回偏移分数,计算方式为:layout shift score = impact fraction * distance fraction。
  • hadRecentInput: 如果 lastInputTime 过去小于 500 毫秒,则返回 true。
  • lastInputTime: 返回最近排除的用户输入的时间,如果没有则返回 0。仅考虑那些用户未期望的偏移,例如在响应用户互动时发生的离散事件,如点击链接、点击按钮或请求API时显示加载等。这些情况被视为合理的偏移。
Long Task

阻塞主线程超过50毫秒的长任务, 可能导致多种不良影响,包括响应事件的延迟和动画卡顿。
当主线程被长任务占用时,浏览器无法及时响应用户输入和处理其他事件,从而影响了用户体验。

主要原因可能是:

  • 长时间运行的事件处理程序(Long-running event handlers)
  • **昂贵的回流(reflow)**和其他重新渲染操作,例如DOM操作、动画等
  • 超过50毫秒的长时间循环
1
2
3
4
5
6
7
8
9
10
11
// Long Task
const observer = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
console.log(entry);
});
});

observer.observe({
type: "longtask",
buffered: true
});

valuet 为 最终 CLS 值,其余参数 解析:

  • duration:表示任务的持续时间,即从开始到结束所经过的时间。
  • TaskAttributionTiming:是与长任务(Long Task)相关的对象,用于追踪和归因长任务的执行。这个对象可能包含关于长任务的详细信息,例如任务的来源、触发事件等。通过这个对象,开发人员可以更好地了解长任务的上下文和原因,从而进行性能优化和调试。

前端监控

⭐️浅谈监控异常采集⭐️

网站压测

Web「性能测试」知多少?