🎬 面试开场怎么引出这个话题
「在中电做过微信小程序商城,从 0 到 1 搭建。上线后发现首屏要 3.2 秒,用户流失严重。我做了系统优化 — 分包加载、图片懒加载、骨架屏、关键请求并行化、setData 优化,最后做到 1.1 秒。这套方法后来也用在了 Web 项目上。性能优化我的体会是:必须先量化(Lighthouse / Performance),找到瓶颈再针对性优化,不能盲目优化。」
✅ 抛出 4 个可深挖的点:① 可量化结果(3.2→1.1)② 系统方法论 ③ 具体手段 ④ 浏览器渲染原理。
性能优化是所有前端岗位必问,有量化数据特别加分。
1

第一原则:先量化,再优化

⚠️ 错误做法

很多前端"优化性能"就是凭感觉 — 加个 lazy、压个图、改个 key。结果:不知道优化了什么、优化了多少、瓶颈还在不在。优化完说不清收益,面试也讲不出。

正确做法: 先用工具量化基线(优化前数据)→ 找到瓶颈 → 针对性优化 → 再量化对比。每个优化都要能说出"提升了多少 ms"。
📋 必须掌握的量化工具
工具看什么适用
LighthouseFCP/LCP/TTI/TBT 评分Web 综合评估
Chrome Performance火焰图、Long Task、主线程占用定位 JS/渲染瓶颈
Network 面板请求瀑布图、资源大小、耗时网络瓶颈
Coverage 面板JS/CSS 未使用率找死代码
WebPageTest多地点多浏览器真实测速线上验证
小程序性能面板启动耗时、setData、渲染小程序
核心指标(必背): FCP(First Contentful Paint):首次内容绘制,白屏结束;
LCP(Largest Contentful Paint):最大内容绘制,首屏完成,目标 < 2.5s;
TTI(Time to Interactive):可交互时间;
CLS(Cumulative Layout Shift):布局偏移,目标 < 0.1。
面试官问"首屏性能看什么指标",答 LCP + FCP。
2

浏览器渲染全链路(优化地图)

🧠 渲染全链路(每个环节都能优化)
DNS 解析 → TCP 连接 → 请求 → 响应 → HTML 解析 → CSSOM → DOM → Render Tree → Layout → Paint → Composite → 可交互
性能优化本质就是缩短这条链路的总耗时。每个环节都有对应手段。
环节瓶颈表现优化手段
DNS/TCP首次连接慢dns-prefetch、preconnect、HTTP/2、CDN
请求/响应资源大、串行压缩、缓存、并行、按需加载
HTML/CSS 解析阻塞渲染CSS 提前、关键 CSS 内联、JS defer/async
JS 执行主线程阻塞代码分割、Tree Shaking、Web Worker
Layout/Paint重排重绘避免强制同步布局、transform 代替 top/left
图片下载慢、解码慢懒加载、WebP、尺寸压缩、响应式图
3

网络层优化

📋 我们项目用过的网络优化
  • 关键请求并行化: 小程序首屏要拉"商品列表 + 用户信息 + 购物车",原来串行(总耗时 = A+B+C),改成 Promise.all 并行(总耗时 = max(A,B,C))
  • 预加载(preload): 关键资源用 <link rel="preload"> 提前下载,不等解析到
  • dns-prefetch / preconnect: 第三方域名提前解析 DNS、建连接
  • HTTP/2: 多路复用,一个连接并行多个请求(要服务器支持)
  • CDN: 静态资源走 CDN,就近访问
  • 缓存策略: 强缓存(Cache-Control) + 协商缓存(ETag),二次访问秒开
收益最大的: 关键请求并行化。我们小程序首屏 3 个请求串行各 500ms = 1.5s,并行后 max(500ms) = 0.5s,直接省 1 秒。这是最立竿见影的优化。
4

资源层优化

📋 资源优化清单
资源优化收益
图片懒加载(IntersectionObserver)、WebP、尺寸压缩、响应式 srcset首屏图片从几 MB 降到几百 KB
JS路由懒加载、代码分割、Tree Shaking、删除死代码主包从 1MB 降到 300KB
CSS提取关键 CSS 内联、Tailwind purge、未使用 CSS 删除阻塞渲染的 CSS 减少
字体font-display: swap、字体子集化(只留用到的字)字体不再阻塞文字
第三方延迟加载、按需引入、自己实现替代大库减少第三方依赖
⚠️ 图片懒加载的坑

图片懒加载要用 IntersectionObserver(现代),别用 scroll 事件监听 + getBoundingClientRect(性能差,频繁触发)。另外要给图片设占位高度,否则图片加载完会"跳一下"(CLS 布局偏移),影响体验评分。

5

渲染层优化

📋 减少 JS 主线程阻塞
  • 路由懒加载: () => import('./X.vue'),首屏只加载首屏代码
  • 代码分割: 把大 vendor 拆分,按需加载
  • 骨架屏: 数据没来先显示骨架,降低"白屏感"
  • 非首屏内容延迟渲染: 用 v-if / requestIdleCallback,先渲染首屏
  • 防抖节流: 滚动、输入等高频事件
JS defer vs async: 这题面试必问。① <script>:阻塞解析,下载执行完才继续;② async:不阻塞解析,下载完立即执行(乱序);③ defer:不阻塞解析,解析完后、DOMContentLoaded 前按顺序执行。首屏 JS 用 defer 最稳。
重排(Reflow) vs 重绘(Repaint): 重排 = 改了几何属性(width/height/position),要重新 Layout,代价大;重绘 = 只改颜色背景,不重新 Layout,代价小。动画用 transformopacity(只触发 Composite,不重排重绘),别用 top/left(触发重排)。
6

小程序专项优化(3.2s → 1.1s 的关键)

手段优化前优化后收益
主包分包所有页面在主包,启动加载全部主包只留首页,其他分包按需-800ms
关键请求并行商品+用户+购物车串行Promise.all 并行-1000ms
图片懒加载列表图全量加载IntersectionObserver 懒加载-400ms
骨架屏白屏等待骨架屏过渡感知-300ms
setData 优化频繁大对象 setData最小化、合并 setData交互更流畅
避免同步 storage启动时同步读 storage异步读或预热-200ms
⚠️ 小程序 setData 的坑

小程序 setData 是跨线程通信(逻辑层 → 渲染层),数据大或频繁调用会卡。优化:① 只传变化的字段(不要整个对象);② 合并多次 setData 为一次;③ 列表用 key 优化 diff;④ 不涉及视图的数据别 setData(用纯变量)。

小程序分包的关键: 小程序主包有大小限制(2MB),且启动时主包全量加载。把非首页放分包,启动只加载主包(首页),进其他页才下载分包。这是我们 3.2→1.1 最大的功臣(-800ms)。
7

高频追问 & 容易翻车点

1首屏性能优化你做了哪些? 必问
按链路分层答: ① 网络层:关键请求并行化(Promise.all)、CDN、HTTP 缓存;② 资源层:路由懒加载、代码分割、图片懒加载 + WebP、Tree Shaking;③ 渲染层:骨架屏、defer JS、关键 CSS 内联;④ 小程序专项:主包分包、setData 优化。每条都要能说出量化收益。
💬 关键:不要泛泛而谈,要"做了什么 + 提升多少 ms"。比如"关键请求从串行改并行,省 1 秒"。
2怎么定位性能瓶颈? 中等
先量化再定位。 ① Lighthouse 看整体评分和 LCP/FCP;② Network 看请求瀑布图,找串行请求和大资源;③ Performance 火焰图找 Long Task(主线程长任务);④ Coverage 找未使用的 JS/CSS;⑤ 针对最大瓶颈优化。原则:80% 收益来自前 20% 优化,先抓大头。
3defer 和 async 区别? 高频
普通 script: 阻塞 HTML 解析,下载执行完才继续。
async: 下载不阻塞,但下载完立即执行(可能打断解析),执行顺序不保证。适合独立第三方脚本(统计)。
defer: 下载不阻塞,解析完后、DOMContentLoaded 前按顺序执行。适合有依赖关系的业务 JS。首屏 JS 用 defer 最稳。
4重排和重绘区别?怎么避免? 高频
重排(Reflow): 改了几何属性(width/height/position),要重新 Layout,代价大。
重绘(Repaint): 只改颜色背景,不重新 Layout,代价小。
避免: ① 动画用 transform/opacity(只 Composite,不重排);② 批量改样式(用 class 切换,别逐个改 style);③ 避免强制同步布局(读 offsetHeight 后立即改样式);④ 离屏 DOM 操作(documentFragment);⑤ 用 will-change 提示浏览器。
5图片优化有哪些手段? 中等
懒加载(IntersectionObserver);② 格式:WebP/AVIF 比 JPG/PNG 小 30-50%;③ 尺寸压缩:按显示尺寸压缩,别传原图;④ 响应式 srcset:不同屏幕加载不同尺寸;⑤ 占位:设宽高防 CLS,用低质量占位图(LQIP);⑥ CDN + 缓存
6LCP / FCP / CLS 分别是什么? 中等
FCP(First Contentful Paint): 首次内容绘制,白屏结束的标志。
LCP(Largest Contentful Paint): 最大内容绘制,首屏主要内容加载完,目标 < 2.5s。
CLS(Cumulative Layout Shift): 累积布局偏移,衡量视觉稳定性,目标 < 0.1(图片没高度会跳,CLS 高)。
这三个是 Google Core Web Vitals 核心指标,面试常问。
7你怎么保证优化效果持续? 加分题
CI 集成 Lighthouse:每次提交自动跑性能测试,分数下降就报警;② 性能预算(Performance Budget):规定 JS 包不能超 X KB,超了构建失败;③ 线上监控:用 Sentry / 阿里 ARMS 监控真实用户的 LCP/FCP;④ Bundle 分析:webpack-bundle-analyzer 定期看包大小变化。性能优化不是一次性的,是持续工程。
💬 这题答出来说明你把性能当工程问题,不只是"优化技巧",非常加分。
8

30 秒电梯陈述(背熟)

🎤 30 秒版
「在中电做微信小程序商城,首屏从 3.2 秒优化到 1.1 秒。我的方法是先量化 — 用小程序性能面板和 Lighthouse 找瓶颈,再针对性优化。最大收益是三个:主包分包(-800ms,启动不全量加载)、关键请求从串行改 Promise.all 并行(-1s)、图片懒加载(-400ms)。另外做了骨架屏降感知白屏、setData 最小化。这套方法论后来也用在 Web 项目。我的体会是性能优化必须数据驱动,每步优化都要能量化收益,而且要持续监控,不是一次性的。」
这段话的优势:
① 有量化结果(3.2→1.1,每项收益)→ 有说服力
② 有方法论(量化→找瓶颈→优化→监控)→ 体系化
③ 有具体手段(分包/并行/懒加载)→ 可深聊
④ 有持续意识(CI 监控)→ 工程思维
性能优化是前端必问,有量化数据 + 方法论,基本能拿分。

面试亮点专题 09 — 首屏性能优化深度话题

量化驱动 · 渲染全链路 · 关键请求并行 · 分包懒加载 · defer/async · 重排重绘 · Core Web Vitals

← 返回专题首页