性能优化说到底是用数据找瓶颈、再验证收益,不是先背一堆方案。
Q1: Core Web Vitals 是什么?为什么重要?
1
指标体系概述:从碎片化到统一标准
早期浏览器性能指标有十几个(FCP、TTI、TBT、FID、LCP、CLS 等),开发者不知道该关注哪个。2020 年 Google 提出 Core Web Vitals,将性能指标精简为三个维度:加载性能(LCP)、交互响应(INP)、视觉稳定性(CLS)。除了这三个核心指标,FCP(First Contentful Paint,首次内容绘制)也是一个重要的辅助指标——它衡量用户何时看到第一个有意义的内容,是感知加载速度的起点。
2
与 SEO 的关系:直接影响搜索排名
Google 从 2021 年起将 Core Web Vitals 作为搜索排名因子。这意味着 LCP、INP、CLS 不仅是用户体验指标,更是直接影响网站流量的 SEO 指标。PageSpeed Insights 和 Search Console 都会展示这些指标的达标情况。
3
Chrome DevTools Performance 面板怎么用
在 Chrome DevTools 中,Performance 面板是分析 Core Web Vitals 的核心工具。录制一段页面加载或用户操作后,面板会展示 FPS(帧率)、Main(主线程任务)、Network(网络请求瀑布图)等关键信息。LCP 会以竖线标记在时间轴上,Layout Shift 会在 Experience 行中高亮显示。
Core Web Vitals 把性能优化从”指标堆砌”简化为”三个核心维度、一组阈值”,让优化有明确的目标,且直接影响 SEO 排名。
没有 Core Web Vitals
就像一个学生不知道考试考什么,语文数学英语物理化学都要复习,精力分散且没有重点。优化了 FCP 但 LCP 变差了,优化了 TTI 但 CLS 变差了,顾此失彼。
引入 Core Web Vitals
就像考试大纲明确告诉你核心只考三门,每门有明确的及格线。你只需要集中精力把 LCP、INP、CLS 考好(≤ 2.5s、≤ 200ms、≤ 0.1),再顺手关注 FCP 这个辅助指标。目标清晰,优化有方向。
Q2: FCP(First Contentful Paint)怎么优化?
FCP(First Contentful Paint,首次内容绘制)衡量从页面开始加载到浏览器渲染出第一个 DOM 内容(文本、图片、SVG、非空白 Canvas)的时间。它是用户感知”页面开始有东西了”的起点。定义与阈值
采集方式
分析方法
在 Chrome DevTools 的 Performance 面板中,FCP 会以绿色竖线标记在时间轴上。点击 Lighthouse 的 Performance 审计,可以看到 FCP 的细分时间:TTFB(服务器响应时间)、DOM 解析时间、关键资源加载时间。优化策略
Q3: LCP(Largest Contentful Paint)怎么优化?
LCP(Largest Contentful Paint,最大内容绘制)衡量页面主要内容的加载速度,本质是从导航开始到最大内容元素渲染完成的时间。定义与阈值
核心优化逻辑只有 4 步:
采集方式
分析方法
Lighthouse 会自动识别 LCP 元素并给出优化建议。Chrome DevTools 的 Performance 面板中,LCP 会以蓝色竖线标记。点击该标记可以看到 LCP 元素的具体信息(类型、URL、尺寸)。优化策略
LCP 的候选元素详解
Q4: CLS(Cumulative Layout Shift)怎么优化?
CLS(Cumulative Layout Shift,累积布局偏移)衡量页面加载过程中元素发生意外位移的程度。它是唯一一个”越小越好”的指标——0 表示没有布局偏移。定义与阈值
CLS 的计算公式:
采集方式
分析方法
Chrome DevTools 的 Performance 面板中,Layout Shift 会在 Experience 行中以红色方块高亮显示。点击方块可以看到具体的偏移元素和偏移距离。Lighthouse 也会列出所有 CLS 来源。优化策略
Q5: INP(Interaction to Next Paint)怎么优化?
INP(Interaction to Next Paint,交互到下一帧绘制)在 2024 年正式替代了 FID(First Input Delay),衡量页面对用户交互的整体响应能力。为什么用 INP 替代 FID?
定义与阈值
采集方式
分析方法
Chrome DevTools 的 Performance 面板录制用户操作后,Interactions 行会显示每次交互的耗时。点击具体的交互条目,可以看到事件处理函数的耗时分解:Input Delay(输入延迟)、Processing Time(处理时间)、Presentation Delay(渲染延迟)。优化策略
Q6: 性能优化的系统性思维
这就是回答”你做过哪些性能优化”的完整框架。 性能优化不是堆砌技术,而是数据驱动的决策过程。系统性优化框架
构建优化
网络优化
渲染优化(Core Web Vitals)
缓存策略
框架优化
CDN 加速原理
CDN(Content Delivery Network,内容分发网络)是网络优化中最核心的一环。理解 CDN 的工作原理,能帮你从”知道要用 CDN”提升到”知道怎么配置 CDN 才最有效”。
CDN 的配置策略:
接口预热
接口预热(API Pre-warming)是指在用户实际请求之前,提前触发接口调用,让服务器缓存或 CDN 边缘缓存进入”热”状态,从而在真实用户请求时直接命中缓存、快速响应。接口预热的核心思想是”把慢的第一次请求提前到用户来之前完成”——通过定时任务、Service Worker 或部署脚本,在用户到达前把缓存填满,让每一次真实请求都命中缓存。
HTTP/2 和 HTTP/3 的优化原理
HTTP 协议的演进直接影响网络优化的上限。HTTP/1.1 的队头阻塞问题催生了 HTTP/2 的多路复用,而 TCP 层的队头阻塞又催生了 HTTP/3 基于 QUIC 的全新传输层。
HTTP/3 QUIC 原理:
HTTP/2 虽然解决了应用层的队头阻塞,但底层 TCP 仍然存在队头阻塞——TCP 保证字节流的有序交付,一个包丢失会阻塞整个连接上的所有流。
HTTP/3 用 QUIC(Quick UDP Internet Connections)替代了 TCP。QUIC 基于 UDP,在传输层实现了独立的流控制:每个流的包丢失只影响该流,不影响其他流。同时 QUIC 将 TLS 1.3 内置到握手中,首次连接只需 1-RTT,后续连接支持 0-RTT。
Q7: 高频面试题
及格回答 vs 满分回答
问题:“说说你做过的性能优化” 及格回答(60-70分):“图片压缩、代码分割、懒加载、CDN、缓存。”问题出在:列举技术点但缺乏数据和框架。 满分回答(90-100分):
我用数据驱动的方式做性能优化。首先用 Lighthouse 和 web-vitals 采集真实用户数据,发现 LCP 是 4.2s(阈值 2.5s),主要瓶颈是首屏图片和关键 CSS。然后按 ROI 排序制定优化方案。
图片优化:从 PNG 转 WebP(体积减少 60%),加<link rel=preload>提前发现资源,用<picture>提供 AVIF/WebP/JPEG 三级降级。非首屏图片用loading="lazy"延迟加载。LCP 从 4.2s 降到 2.1s。关键 CSS 内联到<head>(控制在 14KB 以内,匹配 TCP 初始拥塞窗口),非关键 CSS 异步加载。FCP 从 2.8s 降到 1.5s。[2]
JS 优化:路由级代码分割 +React.lazy,首屏 JS 从 800KB 降到 200KB。Addy Osmani 在《The Cost of JavaScript》中指出,长任务是 INP 的首要元凶——我在长任务中使用scheduler.yield()主动让出主线程,INP 从 350ms 降到 120ms。最终 LCP 2.1s(良好)、FCP 1.5s(良好)、CLS 0.05(良好)、INP 120ms(良好),转化率也有提升。
CLS 优化方面,排查发现两个主要来源:首屏大图没有设置宽高比(加了width/height属性),Web Font 加载导致文字重排(改用font-display: optional)。CLS 从 0.25 降到 0.05。
常见追问
题目来源于真实面经(字节/腾讯/阿里前端面试、牛客网、haizlin/fe-interview),按难度递进。
Core Web Vitals 有哪些? INP 和 FID 有什么区别?
Core Web Vitals 有哪些? INP 和 FID 有什么区别?
答题要点:
必须说出 INP 已经替代了 FID,以及两者测量方式的本质差异。高分回答:
“Core Web Vitals 有三个:LCP(Largest Contentful Paint,最大内容绘制,衡量加载速度,目标 ≤ 2.5s)、INP(Interaction to Next Paint,交互到下一帧,衡量交互响应,目标 ≤ 200ms)、CLS(Cumulative Layout Shift,累积布局偏移,衡量视觉稳定性,目标 ≤ 0.1)。INP 在 2024 年正式替代了 FID(First Input Delay)。核心区别:FID 只测量第一次交互的输入延迟(从用户输入到回调开始执行),不算回调执行时间。INP 测量所有交互中从输入到下一帧视觉更新的完整耗时(包括事件处理、DOM 更新、浏览器绘制),取 P95。所以 INP 更准确地反映了页面的整体交互响应能力——一个页面可能 FID 很好(第一次交互快),但 INP 很差(后续交互卡顿)。”
FCP 和 LCP 有什么区别? 分别怎么优化?
FCP 和 LCP 有什么区别? 分别怎么优化?
答题要点:
区分”首次内容”和”最大内容”,说明两者优化策略的差异。高分回答:
“FCP 衡量浏览器渲染出第一个 DOM 内容的时间(文本、图片、SVG),是用户感知’页面开始有东西了’的起点。LCP 衡量页面最大内容元素渲染完成的时间,是用户感知’主要内容加载完了’的标志。优化 FCP 的重点是减少阻塞:内联关键 CSS(控制在 14KB 以内)、非关键 CSS 异步加载、字体用
font-display: swap。优化 LCP 的重点是资源发现时机:<link rel=preload> 提前发现首屏资源、fetchpriority='high' 优先加载、WebP/AVIF 减少体积、SSR 直出 HTML。最常见的坑:loading='lazy' 误加在首屏图片上——lazy load 会延迟图片加载,严重影响 LCP。”CLS 的 Session Window 算法是怎么算的?
CLS 的 Session Window 算法是怎么算的?
答题要点:
解释 Session Window 的时间窗口和最大值选取逻辑。高分回答:
“CLS 使用 Session Window 算法计算。规则是:5 秒内连续发生的布局偏移算一个 session,session 内所有偏移值累加。如果两次偏移间隔超过 5 秒,就开启一个新的 session。最终 CLS 值取所有 session 中的最大值。关键细节:
- 用户交互(点击、滚动)引起的偏移不计入 CLS(
hadRecentInput属性) - session 的最大持续时间是 5 秒——即使偏移一直持续,超过 5 秒也会被截断
- 这个算法避免了’页面加载完成后持续微小偏移’被无限累加的问题”
INP 的三个阶段分别是什么? 怎么分别优化?
INP 的三个阶段分别是什么? 怎么分别优化?
答题要点:
拆解 INP 的 Input Delay、Processing Time、Presentation Delay。高分回答:
“INP 的完整耗时分为三个阶段:
-
Input Delay(输入延迟):从用户交互到事件回调开始执行的等待时间。瓶颈通常是主线程被其他任务占用。优化:用
scheduler.yield()在长任务中让出主线程。 - Processing Time(处理时间):事件回调的执行时间。优化:拆分长任务、减少 DOM 操作、用 Web Worker 处理计算密集型逻辑。
- Presentation Delay(渲染延迟):从 DOM 更新到浏览器绘制下一帧的等待时间。优化:减少 DOM 节点数(虚拟列表)、避免强制同步布局(读写分离)。
PerformanceObserver 和 getEntries 有什么区别?
PerformanceObserver 和 getEntries 有什么区别?
答题要点:
对比两种 API 的使用场景和优缺点。高分回答:
“两者都能获取性能数据,但使用方式不同:生产环境推荐用 PerformanceObserver,因为它不会遗漏数据,且不会阻塞主线程。”
performance.getEntries() 是拉取模式——需要主动调用获取当前已有的性能条目。适合一次性查询,但可能遗漏后续产生的条目。PerformanceObserver 是推送模式——注册回调后,新的性能条目产生时自动通知。适合持续监控,不会遗漏数据。而且可以用 buffered: true 参数获取注册前已经产生的条目。怎么用 Lighthouse 做性能审计? 结果怎么看?
怎么用 Lighthouse 做性能审计? 结果怎么看?
答题要点:
给出具体的操作步骤和结果解读方法。高分回答:
“Lighthouse 的使用步骤:
- 打开 Chrome DevTools → Lighthouse 面板
- 选择设备(Mobile/Desktop)和审计类别(Performance)
- 点击 Analyze page load
- 用无痕模式录制(排除扩展干扰)
- Performance Score:0-100 分,90+ 为良好
- Core Web Vitals:FCP、LCP、CLS、INP 的具体数值和达标情况
- Opportunities:可优化的建议,按预期收益排序
- Diagnostics:诊断信息,如未使用的 JS/CSS 体积
首屏白屏时间太长怎么排查?
首屏白屏时间太长怎么排查?
答题要点:
给出系统性的排查流程,从网络到渲染逐层定位。高分回答:
“排查首屏白屏,按以下流程逐层定位:
- Network 面板看瀑布图:TTFB 是否过长(> 600ms)?是否有串行请求阻塞?是否有 301/302 重定向?
- Performance 面板看时间轴:JS 执行是否阻塞渲染(Long Task > 50ms)?CSS 是否阻塞 DOM 解析?LCP 元素是什么?什么时候渲染出来的?
- Lighthouse 审计:看 Opportunities 中的建议,按影响排序。
-
具体场景:
- TTFB 长 → 服务端慢,加 CDN、优化接口
- JS 阻塞 → 代码分割、defer/async
- CSS 阻塞 → 内联关键 CSS、preload 非关键 CSS
- 图片阻塞 → preload、WebP/AVIF、fetchpriority
虚拟列表的实现原理是什么? 什么时候该用?
虚拟列表的实现原理是什么? 什么时候该用?
答题要点:
解释可视区域渲染的核心机制,以及适用场景。高分回答:
“虚拟列表(Virtual List)的核心原理是:只渲染可视区域内的 DOM 节点,滚动时动态替换内容。实现步骤:适用场景:万级数据列表、聊天记录、日志查看器。不适用:列表项高度不固定、需要搜索/筛选的场景。”
- 计算可视区域能容纳多少个列表项(
containerHeight / itemHeight) - 根据滚动偏移量计算当前应该显示哪些项(
startIndex = scrollTop / itemHeight) - 用一个占位元素撑开总高度(
totalHeight = itemCount * itemHeight) - 只渲染
startIndex到startIndex + visibleCount的 DOM 节点
CDN 的缓存策略怎么配置? 带 hash 和不带 hash 的资源有什么区别?
CDN 的缓存策略怎么配置? 带 hash 和不带 hash 的资源有什么区别?
答题要点:
区分强缓存和协商缓存的适用场景,说明 hash 命名的作用。高分回答:
“CDN 缓存策略的核心原则是:内容变了就换 URL,没变就用缓存。带 hash 的静态资源(如
main.a1b2c3d4.js):文件内容变化时 hash 变化,URL 随之改变。这类资源应该配置强缓存 Cache-Control: max-age=31536000, immutable——缓存 1 年都没问题,因为新版本会生成新的 URL。不带 hash 的资源(如 index.html):URL 不变但内容可能更新。这类资源应该配置 Cache-Control: no-cache(不是 no-store)——每次使用前向服务器验证是否最新。常见误区:- 用查询参数做版本号(
style.css?v=1.2)——部分 CDN 不缓存带查询参数的请求 - HTML 设置了强缓存——用户永远看不到新版本
- 不同资源的缓存时间没有差异化——频繁更新的资源和几乎不变的资源应该用不同的缓存策略”
HTTP/2 的多路复用和 HTTP/1.1 的 Keep-Alive 有什么区别?
HTTP/2 的多路复用和 HTTP/1.1 的 Keep-Alive 有什么区别?
答题要点:
区分应用层并行和传输层多路复用,指出 Keep-Alive 仍然有队头阻塞。高分回答:
“HTTP/1.1 的 Keep-Alive 只是复用 TCP 连接——多个请求共享一个连接,但必须排队(FIFO),第一个响应没回来,后面的请求全部阻塞。这就是应用层队头阻塞。浏览器被迫开 6 个 TCP 连接来并行加载,但每个连接内仍然是串行的。HTTP/2 的多路复用是真正的并行——一个 TCP 连接被分成多个流(Stream),不同流的帧(Frame)可以交错发送。请求 A 的响应慢,不影响请求 B 的帧传输。还有一个关键区别:HTTP/1.1 的 Keep-Alive 连接有空闲超时(通常 60-120 秒),超时后连接关闭需要重新建立。HTTP/2 的连接更加持久,且支持服务端主动推送(Server Push,虽然已被废弃)。HTTP/3 进一步解决了 TCP 层的队头阻塞:基于 QUIC/UDP,每个流独立控制丢包重传,一个流的丢包不影响其他流。“
底层源码:Chrome 是如何测量性能指标的?
Chrome 的 LCP 观测是怎么实现的?
Chrome 的 LCP 观测实现在 LargestContentfulPaint 类中(详见 Blink 源码:largest_contentful_paint.cc):
INP 是怎么测量的?
详见 Blink 源码:event_timing.cc:
延伸阅读与引用参考
- Web Vitals 官方文档:Google 对 Core Web Vitals 指标的权威定义和优化建议。INP 于 2024 年 3 月 12 日正式替代 FID,测量所有交互的完整耗时(P95),而非仅第一次交互的输入延迟。[1]
- Lighthouse 性能审计指南:Chrome 官方对 Lighthouse 工具的使用方法和指标解读。[2]
- Chrome DevTools Performance 面板文档:Chrome 官方对性能面板的使用方法和指标解读。[3]
- web-vitals 库:Google 官方的 Core Web Vitals 采集库,生产环境推荐使用。[4]
- INP migration guide:web.dev 对 FID 到 INP 迁移的官方指南,解释了 INP 的三个阶段(Input Delay、Processing Time、Presentation Delay)。
- Long Animation Frames (LoAF) API:Chrome 新推出的诊断主线程瓶颈的 API,比 Long Tasks 更精确。
- 李兵 极客时间《浏览器工作原理与实践》:将渲染流水线拆解为 Style → Layout → Paint → Composite 四阶段,给出每帧 16.6ms 的时间分配模型。
- Inside look at modern web browser:Lin Clark 在 Chrome Developers 发表的四部曲系列(2018),用漫画解析 Chromium 多进程架构和渲染流水线。
- The Cost of JavaScript:Addy Osmani 在 V8 官方博客发表的文章,讨论长任务对交互响应的影响,并介绍用
scheduler.yield()等方式拆分长任务。
