Web 性能监控 —— Performance

180 阅读7分钟

Web 性能监控 —— Performance

Web 性能是 Web 开发的一个重要方面,侧重于网页加载速度以及对用户输入的响应速度。

性能指标

Web 性能指标分为两种,一种是 Core Web Vitals,一种是其他。

🔶 Core Web Vitals

🔹 Largest Contentful Paint(LCP) :视口内最大内容(文本块、图片、视频)的渲染时间,衡量加载性能。2.5 秒为优秀。

🔹 Interaction To Next Paint(INP) :用户所有互动的最大延迟时间,衡量互动性。200 毫秒为优秀。

🔹 Cumulative Layout Shift(CLS) :累计布局偏移,衡量视觉稳定性。0.1 为优秀。

🔶 其他指标

🔹 Time To First Byte(TTFB) :衡量请求资源到响应第一个字节开始到达之间的时间,网页的 TTFB 应不超过 0.8 秒

🔹 First Contentful Paint (FCP) :衡量从用户首次导航到网页到网页任何一部分内容呈现在屏幕上的时间,网页的 TTFB 应不超过 1.8 秒

🔹 Total Blocking Time (TBT) :衡量从 FCP 之后主线程处于屏蔽状态的时间总和,网页的总屏蔽时间不超过 200 毫秒

Performance 面板

Performance 面板最大的作用是 实时录制 网页性能变化,让开发人员可以利用 时间轴 逐帧分析性能问题。

1️⃣ 在无痕模式下打开 Google Chrome,确保 Chrome 在干净状态下运行。如果您安装了许多扩展程序,扩展程序可能会在性能衡量中产生影响。

2️⃣ 加载页面 https://googlechrome.github.io/devtools-samples/jank/。

3️⃣ 打开 Devtool,切换至 Performance 面板。

Performance 面板里面有一些设置:

🔶 CPU 节流,模拟低性能设备的处理能力,建议选择 4x 或 6x 节流,可以更真实地观察长任务、交互延迟等问题。

🔶 网络节流,模拟不同网络环境,建议使用 Slow 3G 来测试首屏加载、资源阻塞、LCP 等指标。

🔶 屏幕截图,录制性能时间线时自动捕捉页面截图,方便定位视觉变化,开启后可以直观看到 FCP、LCP 等关键帧,尤其适合分析首屏渲染。

🔶 高级绘制插桩,记录更详细的绘制信息,包括哪些区域被重绘、绘制成本,适合分析频繁重排、重绘的页面,尤其是动画或复杂布局。

🔶 显示自定义跟踪记录,显示通过 performance.mark()performance.measure() 创建的自定义条目。

🔶 CSS 选择器分析,分析哪些 CSS 选择器在渲染过程中最耗性能,适合优化大型样式表,找出影响重排的选择器。

里面还有一个关于 Chrome UX Report 设置真实用户的配置,Chrome UX Report 收录是有条件的:

1️⃣ 用户使用 Chrome 浏览器,并开启了匿名使用统计。

2️⃣ 网站访问次数超过 Chrome 的门槛。

3️⃣ 网站是 HTTPS 协议。

所以一般都是使用 web-vitals 编写采集脚本发送到自己的服务器进行分析。

image-20250920215808676

在左侧 Insights 标签页可以看到 LCP、INP、CLS 三个 Core Web Vitals,下方展开的是可以优化的项目,已通过的数据分析会折叠起来。

右侧 Annotations 是做标记的,你可以在 主要(main) 图表中为跟踪记录添加注释,也可以关联两个跟踪记录,方便他人查看。

image-20250920220556456.png

红色的是 FPS 图表。看到红色条时,就表示帧速率下降得太低,可能会影响用户体验。

CPU 图表中的颜色与性能面板底部的摘要标签页中的颜色相对应。如果 CPU 图表呈现全彩,则表示 CPU 在记录期间已达到上限。

将鼠标悬停在 FPSCPUNET 图表上。开发者工具会显示相应时间点的网页屏幕截图(需要勾选屏幕截图)。

image-20250920220919999.png

这是一个长任务的截图,灰色部分是 50ms,超过 50ms 会有红色网格标记,同时右上角有红色小三角形标记。

image-20250920221100054.png

这是调用栈的截图,你点击任意一个跟踪记录,在下方摘要可以看到具体的调用栈,然后通过调用栈跳转到具体代码。

image-20250920221255118.png

可以看到 app.update 在录制期间一共耗时 810.1 ms。

以上就是 Performance 面板的作用了。

Performance 和 Lighthouse 的区别

Performance 和 Lighthouse 是浏览器开发者工具中的两个重要模块,它们都用于分析网页性能,但关注点和使用方式略有不同。

🔶 Lighthouse 提供的是自动化审查报告,适合快速了解整体表现和优化建议。

🔶 Performance 面板则是手动分析工具,适合深入研究每一帧的渲染、脚本执行、网络请求等细节。

Lighthouse 的性能评分部分会调用浏览器的 Performance API,所以 Performance 和 Lighthouse 会有数据重叠。

功能模块LighthousePerformance
类型自动化审查工具手动性能分析工具
使用方式一键生成报告录制页面行为并分析时间线
输出内容性能评分、建议、SEO、可访问性等精细的时间线、帧率、内存、CPU 使用情况等
适合场景快速诊断、CI 集成、非技术人员查看深度调试、性能瓶颈定位、开发者优化
是否依赖真实用户操作否(模拟加载)是(可录制真实交互)

Performance API

当网站达不到 Chrome UX Report 收录条件,需要我们使用采集脚本进行采集时,就用到了 Performance API 了。

常用 API

performance.now()

performance.now() 返回一个当前页面开始加载导航开始 到 调用 performance.now() 的 亚毫秒级的毫秒数。

performance.now() 一般用于简单的一次性测量、不跟踪性能条目或者配合 requestAnimationFrame 使用。

 // 一次性测量
 const t0 = performance.now();
 // 这里是你要测量的一段代码...
 const t1 = performance.now();
 console.log(`代码执行耗时: ${t1 - t0} 毫秒`);
 ​
 // 配合 requestAnimationFrame 使用
 // requestAnimationFrame 回调的第一个参数也是 DOMHighResTimeStamp,跟 performance.now() 相似
 let lastTime = performance.now();
 ​
 function animate(currentTime) {
   const deltaTime = currentTime - lastTime;
   // 根据 deltaTime 更新动画位置、状态等
   console.log(`两帧之间的时间差: ${deltaTime} 毫秒`);
   lastTime = currentTime;
   requestAnimationFrame(animate);
 }
 ​
 requestAnimationFrame(animate);
mark/clearMark、measure/clearMeasure、getEntries/getEntriesByName/getEntriesByType

mark 和 measure 通常配合使用,它会跟踪性能条目中,也就是你可以在 Performance 面板中,通过勾选显示自定义跟踪看到该条目。

     // 以一个标志开始。
     performance.mark("mySetTimeout-start");
     ​
     // 等待一些时间。
     setTimeout(function () {
       // 标志时间的结束。
       performance.mark("mySetTimeout-end");
     ​
       // 测量两个不同的标志。
       performance.measure("mySetTimeout", "mySetTimeout-start", "mySetTimeout-end");
     ​
       // 获取所有的测量输出。
       var measures = performance.getEntriesByName("mySetTimeout");
       var measure = measures[0];
       console.log("setTimeout milliseconds:", measure.duration);
     ​
       // 清除存储的标志位
       performance.clearMarks();
       performance.clearMeasures();
     }, 1000);
PerformanceObserver

Performance API 可以简单分为 全局的 window.performance 对象和 PerformanceObserver 类。前者是主动出击记录性能条目,后者是被动记录性能条目。

基本用法

     function perfObserver(entries, observer, {droppedEntriesCount}) {
         entries.getEntries().forEach((entry) => {
             if (entry.entryType === "mark") {
                 console.log(`${entry.name}'s startTime: ${entry.startTime}`);
             }
             if (entry.entryType === "measure") {
                 console.log(`${entry.name}'s duration: ${entry.duration}`);
             }
             if (options?.droppedEntriesCount > 0) {
                 console.log('删除的条目数量:', options?.droppedEntriesCount)
             }
         });
     }
     const observer = new PerformanceObserver(perfObserver);
     observer.observe({ entryTypes: ["measure", "mark"] });

PerformanceObserver.observe() 方法支持的 entryTypes 的详细表格,同时包含了每个类型的接口类型和作用。

entryType接口类型作用
"mark"PerformanceMark表示通过 performance.mark() 方法创建的自定义性能标记,用于标记代码中的特定时间点。
"measure"PerformanceMeasure表示通过 performance.measure() 方法创建的自定义性能测量,用于计算两个标记点之间的时间间隔。
"resource"PerformanceResourceTiming提供了所有页面资源的加载时间信息,例如 CSS、JavaScript、图片等,可以获取重定向、DNS 查询、TCP 连接等详细数据。
"navigation"PerformanceNavigationTiming提供了页面导航的详细计时信息,例如从点击链接到 DOM 解析完成、加载事件结束等各个阶段的时间。
"paint"PerformancePaintTiming用于记录与页面渲染相关的关键时间点,目前主要包括 First PaintFirst Contentful Paint
"longtask"PerformanceLongTaskTiming用于识别耗时过长的任务,通常指在主线程上运行超过 50 毫秒的 JavaScript 代码,这些任务可能会导致页面卡顿。
"largest-contentful-paint"PerformancePaintTiming记录 最大内容绘制 (LCP) 的时间,它是衡量页面加载性能的核心 Web Vitals 指标。
"layout-shift"LayoutShift记录页面布局的意外偏移,用于衡量 累计布局偏移 (CLS) ,是评估页面视觉稳定性的核心 Web Vitals 指标。
"first-input"PerformanceEventTiming记录用户首次与页面交互(如点击或按键)到浏览器开始处理该事件之间的时间,用于衡量 首次输入延迟 (FID) ,是评估页面交互响应性的核心 Web Vitals 指标。