前言
前段时间面wxg总算是见识到了啥叫要求高了,疯狂被问『是怎么做的?』「为什么这么做?」「你了解过它的底层原理吗?」😫真的被问裂开了,没学的不知道,学了的记不住🤯顾不住工作的疲劳了,加班给自己系统整理下知识链路吧hai🙃
正篇
本文结构计划为:性能指标介绍 -> Lighthouse 性能指标 与 Core Web Vitals 的指标 对比 -> 深入了解Performance API -> 性能指标是怎么计算出来的 -> 应用场景粗略介绍 ->
性能指标介绍
先来看下Lighthouse中有哪些核心性能指标
指标 | 介绍 |
---|---|
FCP 首次有内容渲染 | First Contentful Paint 在性能统计指标中,从用户开始访问页面的时间点 到FCP的时间点这段时间可以被视为无内容时间,也就是说中用户访问Web页面的过程中,FCP时间点之前,用户看到的都是没有任何内容的屏幕,在这个阶段获取不到任何有用的信息。 |
LCP 最大内容渲染 | Largest Contentful Paint LCP表示用户开始访问页面的时间点 到可视区域内可见的最大(尺寸)图片或文本块完成渲染的相对时间。相对于FCP测量初始DOM内容完成渲染所需的时间,但无法捕获页面上最大内容渲染所需的时间,LCP更能体现屏幕可视区元素渲染的用户体验,因为最大的内容通常也是最有意义的。LCP在2.5秒内达到快速级别。 |
TBT 总阻塞时间 | Total Blocking Time 页面加载过程中,主线程被长时间任务(通常是 JavaScript 执行)阻塞的总时间。 |
CLS 累积布局偏移 | Cumulative Layout Shift 页面加载过程中发生的意外布局变化的总量,可能导致用户在交互时误触或出现不良体验。 |
SI 速度指数 | Speed Index 用于衡量页面可视区域内容填充的速度,它是页面可视区域内容填充花费的平均时间,通常3.4秒内可达快速等级。 |
后续在阅读一些 Lighthouse 指标相关文章的时候发现,好像每次展现出来的指标不是固定的,并且还有另外一套衡量网页用户体验 的核心指标体系:"Core Web Vitals", 有意思,一起来研究下这两套体系有啥区别。
体系比对
-
"Core Web Vitals" 是谷歌提出的用于衡量网页用户体验的核心指标体系 ,主要聚焦于网页的加载性能、交互响应和视觉稳定性。
-
"Lighthouse" 是谷歌开发的网页性能检测工具 ,其性能指标体系与 Core Web Vitals(CWV)既有重叠又有差异,是开发者的 "诊断工具",面向技术优化
一、Lighthouse 性能指标与 Core Web Vitals 的指标对比
- Core Web Vitals(CWV)核心指标
指标 | 类型 | 核心关注点 | 属于 Lighthouse 吗? |
---|---|---|---|
LCP | 加载性能 | 主内容可见速度 | 是(性能报告中包含) |
FID | 交互响应 | 首次操作延迟 | 是(性能报告中包含) |
CLS | 视觉稳定性 | 布局偏移程度 | 是(性能报告中包含) |
- Lighthouse 性能指标体系(更全面)
指标分类 | 具体指标 | 与 CWV 的关系 |
---|---|---|
加载性能 | LCP、FCP、TTFB、TTI | LCP 是 CWV 核心,FCP/TTFB/TTI 为辅助 |
交互响应 | FID、长任务(Long Tasks) | FID 是 CWV 核心,长任务影响 FID |
视觉稳定性 | CLS | 与 CWV 完全一致 |
资源效率 | 总阻塞时间(TBT)、JavaScript 执行时间 | 影响 FID 和 TTI |
字节效率 | 首次加载字节数、重复访问字节数 | 影响 LCP 和整体加载速度 |
渲染效率 | 主线程利用率、样式计算时间 | 影响 FCP 和 LCP |
二、核心区别:指标的 "聚焦度" 与 "用途" 不同
- CWV:用户体验的 "核心门槛",面向普通用户和搜索引擎
-
特点:仅包含 3 个最关键指标(LCP/FID/CLS),直指用户对网页的三大核心体验痛点:
- LCP:"能不能快速看到内容"
- FID:"点了有没有反应"
- CLS:"页面会不会乱跳"
-
目的:
- 作为谷歌搜索排名的参考因素,推动网站优化基础体验;
- 用极简指标让非技术人员也能理解网页体验好坏。
- Lighthouse 性能指标:开发者的 "诊断工具",面向技术优化
-
特点:包含 20+ 细分指标,覆盖从加载、渲染到交互的全流程,例如:
- FCP(首次内容绘制) :比 LCP 更早监测页面初始视觉反馈,定位首屏渲染问题;
- TTI(可交互时间) :衡量页面完全可操作的时间,比 FID 更全面;
- TBT(总阻塞时间) :分析 JavaScript 阻塞主线程的时长,直接影响 FID 和 TTI。
-
目的:
- 为开发者提供详细的性能瓶颈定位,例如 "LCP 慢" 可能由 TTFB 长、图片未优化等多种原因导致,Lighthouse 会细分到具体环节;
- 支持自定义评分规则(如可调整指标权重),适应不同业务场景的优化需求。
三、为什么要这样分类?------ 从 "用户体验" 和 "技术实现" 双维度理解
- CWV 的分类逻辑:以 "用户直觉体验" 为核心
- 用户不会关心 "TTFB 是 200ms 还是 300ms",但能直观感受到 "页面加载慢""点按钮没反应""广告突然挤掉内容"。
- CWV 用最简化的指标将技术参数转化为用户可感知的体验,降低理解门槛,同时通过搜索引擎排名强制推动行业优化基础体验。
- Lighthouse 的分类逻辑:以 "技术诊断" 和 "全链路优化" 为目标
- 开发者需要知道 "问题出在哪":例如 LCP 慢,可能需要分析 TTFB(服务器问题)、FCP(渲染问题)、资源加载顺序(代码问题)等细分指标。
- Lighthouse 的多层级指标体系如同 "性能解剖图",既能定位表层问题(如 LCP 超时),又能深入技术细节(如某个 JavaScript 函数阻塞了主线程),帮助开发者制定精准优化方案。
四、两者的关系:CWV 是 Lighthouse 的 "子集",但定位不同
-
包含关系:CWV 的 3 个指标均来自 Lighthouse 性能报告,但 Lighthouse 提供了更丰富的上下文数据。
-
互补关系:
-
非技术人员(如产品经理)可通过 CWV 快速判断网页体验好坏;
-
开发者则需结合 Lighthouse 全指标分析,例如:
- 若 LCP 超时,需查看 FCP、TTFB、资源加载瀑布图等定位原因;
- 若 FID 过高,需分析长任务、JavaScript 执行时间等细分指标。
-
五、总结:分类的本质是 "目标用户与场景的差异化"
维度 | Core Web Vitals | Lighthouse 性能指标 |
---|---|---|
目标用户 | 产品经理、运营、普通用户、搜索引擎 | 开发者、性能优化工程师 |
核心价值 | 定义 "好体验" 的最低标 | 提供 "如何优化" 的全流程诊断工具 |
指标数量 | 3 个极简指标 | 20+ 细分指标 |
应用场景 | 评估、排名、市场竞争 | 开发、调试、技术优化 |
这种分类方式既满足了大众对 "用户体验" 的直观认知,又为技术优化提供了精细化的操作空间,形成了从 "体验评估" 到 "技术实现" 的完整闭环。
插个题外知识:非指标的性能(页面流畅度)还可以用什么来衡量呢?
--游戏玩家也许会比较熟悉:「帧率(FPS)」直观感受不同帧率的体验:
- 50~60FPS:相当流畅,让人倍感舒适。
- 30~50FPS:因各人敏感程度不同,舒适度因人而异。
- 30FPS以下:让人感觉到明显的卡顿和不适感。
在Chrome 的 devtools 中我们可以执行 Cmd+Shift+P 输入 show fps 来快速打开fps面板。
页面性能这一块真的好多内容可以聊,到这里还没完呢,要学就学个彻底(不然面试遇到拷打就跟坐牢一样)--- Performance API来了解一下。
深入了解Performance API
啥是PerformanceAPI?
-
PerformanceAPI
是浏览器提供的一组用于获取网页性能数据的工具 ,用于精确度量、控制、增强浏览器的性能表现,使测量网站性能达到前所未有的精度
*功能特性
- 高精度时间测量 :提供高精度的时间戳,如
performance.now()
方法,单位为毫秒,精度可达微秒,相比Date.now()
,它不受系统时间调整的影响,能更精准地测量代码执行时间。 - 详细性能信息获取 :通过
performance.timing
属性,可以获取详细的页面加载阶段的时间数据,帮助开发者了解页面加载的每个阶段,如 DNS 查询、资源下载等,快速定位性能瓶颈。 - 资源加载监控 :
performance.getEntriesByType()
方法可获取资源加载的详细信息,例如图片、脚本等文件的加载时间,便于识别加载缓慢的资源,从而进行针对性优化。 - 自定义性能标记和测量 :
performance.mark()
和performance.measure()
方法允许开发者在代码中标记特定的点,并测量这些点之间的时间间隔,精确定位性能瓶颈。
常用接口及作用
- PerformanceTiming 接口:提供更详细的页面加载时间信息,包括各个阶段的开始和结束时间,是测量页面性能的重要接口。
- PerformanceNavigation 接口:提供有关页面导航的信息,如重定向次数、是否通过缓存加载等,帮助开发者了解页面导航过程中的性能指标。
- PerformanceEntry 接口:提供有关特定资源或事件的详细性能信息,如资源加载时间、事件处理时间等,用于监控和分析特定资源或事件的性能。
应用场景
- 优化代码执行时间 :通过在代码的关键部分使用
performance.now()
、performance.mark()
和performance.measure()
等方法,可以测量代码的执行时间,找出耗时较长的部分,进行针对性的优化。 - 优化页面加载速度 :利用
performance.timing
和performance.getEntriesByType()
等接口获取页面加载和资源加载的性能数据,找出加载时间较长的资源,采取启用 CDN、代码分割、优化图片等措施来加速页面加载。 - 监控用户交互性能:可以在用户进行交互操作(如点击按钮、滚动页面等)时,使用 Performance API 记录相关的时间数据,了解用户与网页的交互体验,发现并解决交互过程中存在的性能问题。
- 高精度时间测量 :提供高精度的时间戳,如
了解完啥是Performance,现在可以来关注一下PerformanceTiming接口的详细字段,来上图⬇️

字段名 | 意义 |
---|---|
navigationStart | 浏览器准备开始导航到页面的起始时间。 若通过点击链接、书签或表单提交等方式导航,此值为用户操作触发的时间; 若是通过脚本(如 location.href )导航,则为脚本执行的时间。 |
unloadEventStart | 前一个页面(如通过重定向或 history.back() 访问的页面)的 unload 事件开始的时间。 若无前一个页面或前一个页面未触发 unload 事件,则值为 0 。 |
unloadEventEnd | 前一个页面的 unload 事件结束的时间。 若无前一个页面或前一个页面未触发 unload 事件,则值为 0 。 |
redirectStart | 第一个 HTTP 重定向开始的时间。 若没有重定向(或重定向非同源),则值为 0 。 |
redirectEnd | 最后一个 HTTP 重定向完成的时间(即响应的最后一个字节接收完毕)。 若没有重定向(或重定向非同源),则值为 0 。 |
fetchStart | 浏览器开始获取资源(如 HTML、JSON 等)的时间。 若存在重定向,此值为最后一次重定向后开始获取资源的时间。 |
domainLookupStart | DNS 查询开始的时间。 若使用缓存或本地解析(如 localhost ),则此值等于 fetchStart 。 |
domainLookupEnd | DNS 查询完成的时间。 若使用缓存或本地解析,则此值等于 fetchStart 。 |
connectStart | TCP 连接开始的时间。 若使用持久连接(如 HTTP/2)或连接已建立,则此值等于 domainLookupEnd 。 |
secureConnectionStart | TLS/SSL 握手开始的时间。 若请求非 HTTPS 协议或使用持久连接,则值为 0 。 |
connectEnd | TCP 连接(及 TLS 握手,若适用)完成的时间。 |
requestStart | 浏览器向服务器发送 HTTP 请求的开始时间(即请求的第一个字节发出)。 |
responseStart | 浏览器从服务器接收 HTTP 响应的开始时间(即响应的第一个字节收到)。 |
responseEnd | 浏览器接收完响应的最后一个字节的时间。 |
domLoading | 浏览器开始解析 HTML 文档的时间(即 document.readyState 变为 'loading' )。 |
domInteractive | 浏览器完成 HTML 解析并开始构建 DOM 树的时间(即 document.readyState 变为 'interactive' )。此时,DOM 树已构建完成,但外部资源(如脚本、样式表、图片)可能仍在加载。 |
domContentLoadedEventStart | DOMContentLoaded 事件触发的时间。 此时,DOM 树已构建完成,且无需等待样式表、图片等外部资源加载完成。 |
domContentLoadedEventEnd | DOMContentLoaded 事件处理完成的时间。 |
domComplete | 页面所有资源(包括图片、iframe 等)加载完成的时间(即 document.readyState 变为 'complete' )。 |
loadEventStart | load 事件触发的时间。 此事件在 domComplete 之后触发,表示页面完全加载完成。 |
loadEventEnd | load 事件处理完成的时间。 至此,页面加载全过程结束。 |
思考下:有了这些指标,可以用来干嘛?(其实就是用performanceAPI计算性能指标的原理所在,
Performance API 依赖浏览器内核提供的高精度时间戳,其核心原理是基于 单调时间(Monotonic Time) ,而非系统时间(Wall Clock Time)。
- 单调时间的优势 :不受系统时间调整(如手动修改时间、NTP 同步)影响,确保时间间隔计算的准确性。例如,
performance.now()
返回的是从浏览器启动到当前的毫秒数,精度可达微秒级(1ms = 1000μs)。- 底层实现 :浏览器通过操作系统接口(如 Linux 的
clock_gettime(CLOCK_MONOTONIC)
、Windows 的QueryPerformanceCounter
)获取单调时间,并封装为DOMHighResTimeStamp
类型。
- 页面加载阶段指标(基于 PerformanceTiming)
以下指标均通过 事件触发时间戳的差值 计算,按页面加载流程顺序说明:
指标名称 | 计算公式 | 原理说明 |
---|---|---|
DNS 查询耗时 | domainLookupEnd - domainLookupStart |
浏览器在 fetchStart 后触发 DNS 查询,记录开始与结束时间戳。若使用缓存,两者相等(耗时为 0)。 |
TCP 连接耗时 | connectEnd - connectStart |
包含 TCP 三次握手(及 TLS 握手,若为 HTTPS)的时间。connectStart 为开始建立连接的时间,connectEnd 为连接成功的时间。 |
HTTP 请求响应耗时 | responseEnd - requestStart |
从浏览器发送请求(requestStart )到接收完响应数据(responseEnd )的时间,包含网络传输与服务器处理时间。 |
DOM 解析耗时 | domInteractive - domLoading |
domLoading 表示 HTML 解析开始,domInteractive 表示 DOM 树构建完成,两者差值为解析 HTML 的耗时。 |
资源加载耗时 | domComplete - domInteractive |
domInteractive 后,浏览器开始加载外部资源(如图片、脚本),domComplete 表示所有资源加载完成。 |
首屏时间(FP/FCP) | 需结合 PerformancePaint API ,通常取 firstContentfulPaint 时间戳 |
传统 PerformanceTiming 无直接首屏指标,现代浏览器通过 PerformancePaint 记录首次绘制内容的时间(如文本、图片)。 |
完全加载时间 | loadEventEnd - navigationStart |
从导航开始到 load 事件处理完成的总耗时,包含所有资源加载与脚本执行时间。 |
- 用户交互性能指标(基于 PerformanceMark/Measure)
开发者可自定义标记点,通过 时间戳差值 计算特定流程的耗时:
- 示例:按钮点击到响应的耗时
javascript
// 标记点击开始
performance.mark('buttonClickStart');
// 按钮点击事件处理函数
button.addEventListener('click', () => {
// 业务逻辑
// 标记点击结束
performance.mark('buttonClickEnd');
// 计算耗时
performance.measure('buttonResponseTime', 'buttonClickStart', 'buttonClickEnd');
// 获取结果
const measure = performance.getEntriesByName('buttonResponseTime')[0];
console.log(`按钮响应耗时:${measure.duration}ms`);
});
原理 :通过 performance.mark()
记录自定义事件的时间戳,performance.measure()
计算两个标记点的时间差,底层依赖单调时间确保精度。
- 资源加载性能指标(基于 PerformanceResourceTiming)
通过 performance.getEntriesByType('resource')
获取单个资源的加载数据,核心指标计算:
- 资源加载总耗时 :
responseEnd - startTime
(startTime
为资源开始请求的时间)。 - 网络传输耗时 :
responseEnd - requestStart
(排除服务器处理时间)。 - 缓存命中耗时 :若
fromCache
为true
,则耗时极短(仅读取缓存的时间)。
光获取性能指标没啥用,要转化收益还是得针对性能问题去有针对性地优化
性能指标的应用场景与优化方向(略写如下)
- DNS耗时过长 :
- 原因:域名未被缓存,或DNS服务器响应慢
- 优化:使用DNS预解析(
<link rel="dns-prefetch">
),或选择更快的DNS服务(如Cloudflare DNS)
- TCP连接耗时过长 :
- 原因:首次连接需三次握手,HTTPS还需TLS握手
- 优化:启用HTTP/2(复用连接)、使用Keep-Alive保持长连接,或部署CDN减少物理距离
- DOM解析耗时过长 :
- 原因:HTML文档过大,或包含阻塞渲染的脚本/样式表
- 优化:拆分HTML、异步加载非关键脚本(async/defer)、使用CSS媒体查询(media="print"等)避免阻塞。
- 资源加载耗时过长 :
- 原因:图片未压缩、脚本体积过大、CDN节点离用户太远
- 优化:使用WebP图片、代码分割(import())、启用懒加载(loading="lazy")、切换CDN节点。
现代浏览器的性能监控优化
随着Web标准发展,除了PerformanceTiming,还新增了更精准的指标接口:
接口名称 | 用途 |
---|---|
PerformancePaint API | 记录首次渲染(FP)、首次内容渲染(FCP)、最大内容渲染(LCP)等首屏相关时间 |
PerformanceEntryTiming API | 细化资源加载阶段(如responseStart到responseEnd可拆分为transferStart和transferEnd) |
User Timing API | 允许开发者自定义性能指标(如接口响应时间、动画流畅度等) |
本文的篇幅有点太长了,侧重点在于扩展比较枯燥的知识面,更有意思的应用场景,以及性能指标的详解就没有铺开来写,后面计划会针对应用场景和性能指标详解各写一篇详细的🫠