前端性能优化
一、性能指标与衡量
Q1:前端常见性能指标有哪些?分别代表什么?
答:
FP(First Paint):首次绘制,页面开始有像素渲染。
FCP(First Contentful Paint):首次内容绘制,出现文本/图片等真实内容。
LCP(Largest Contentful Paint):最大内容绘制,核心体验指标,要求 < 2.5s。
FID(First Input Delay):首次输入延迟,用户交互到浏览器响应的时间,要求 < 100ms。
CLS(Cumulative Layout Shift):累积布局偏移,页面布局跳动,要求 < 0.1。
TTI(Time to Interactive):可交互时间,页面稳定可交互。
TTFB(Time to First Byte):首字节时间,网络+服务端响应速度。
Q2:如何做性能监控?常用工具/方案?
答:
实验室数据:Lighthouse、WebPageTest、Chrome DevTools(Performance/Network)。
真实用户监控(RUM):
用
PerformanceObserver监听 LCP、FID、CLS。用
PerformanceTiming/Navigation Timing API收集加载数据。上报到 Sentry、阿里云 ARMS、自研监控平台。
长任务监控:
PerformanceObserver监听longtask,定位阻塞主线程的任务。
Q3:什么是长任务?如何定位与优化?
答:
长任务:执行时间 > 50ms、阻塞主线程的任务,会导致卡顿、交互延迟。
定位:
Chrome Performance 面板看长任务条。
PerformanceObserver上报长任务。
优化:
拆分长任务:
setTimeout、requestIdleCallback、queueMicrotask。耗时计算放到 Web Worker。
懒执行非首屏逻辑。
二、网络与加载优化(最常问)
Q4:HTTP 缓存(强缓存/协商缓存)完整流程?
答:
强缓存:不发请求,直接用本地。
Cache-Control: max-age=xxx(相对时间,优先)Expires(绝对时间,兼容)
协商缓存:发请求,服务器判断是否可用。
响应:
Last-Modified/ETag请求:
If-Modified-Since/If-None-Match304 用缓存,200 用新内容。
优先级:
Cache-Control>Expires;ETag>Last-Modified。
Q5:HTTP1.1 / HTTP2 / HTTP3 对性能的影响?
答:
HTTP1.1:队头阻塞、单连接串行、头信息大。
HTTP2:二进制分帧、多路复用、头部压缩、服务器推送,解决队头阻塞。
HTTP3:基于 QUIC(UDP),彻底解决 TCP 队头阻塞,0-RTT 握手更快。
Q6:资源加载优化手段(按优先级)?
答:
减少请求数:雪碧图、资源合并、接口合并、内联小资源。
压缩体积:Gzip/Brotli、JS/CSS/HTML 压缩、图片 WebP/AVIF。
懒加载:图片懒加载、路由懒加载、组件懒加载、Intersection Observer。
预加载/预连接:
dns-prefetch:提前解析 DNSpreconnect:提前建立连接preload:关键资源优先加载prefetch:预测下一页资源
CDN:静态资源上 CDN,就近访问。
接口优化:合并接口、分页、防抖、缓存接口数据。
Q7:图片优化有哪些手段?
答:
格式:WebP/AVIF/PNG 代替 JPG,SVG 代替小图标。
响应式图片:
srcset+sizes,根据屏幕加载对应尺寸。懒加载:
loading="lazy"或 Intersection Observer。占位:低质量图片占位(LQIP)、SVG 占位、骨架屏。
压缩:TinyPNG、Squoosh、webpack-image-minimizer。
避免布局偏移:给图片固定宽高或
aspect-ratio。
三、渲染优化(重排/重绘/合成)
Q8:重排(reflow)、重绘(repaint)、合成(composite)区别?
答:
重排:修改几何属性(宽高、位置、display)→ 重新布局,开销最大。
重绘:修改样式但不影响布局(color、background)→ 只重画像素。
合成:transform/opacity 等在合成线程处理 → 不触发重排重绘,开销最小。
Q9:如何减少重排重绘?
答:
批量修改 DOM:使用文档片段
DocumentFragment。离线 DOM:先
display: none,修改完再显示。读写分离:不要“读布局属性 → 立即修改 → 再读”,避免强制同步布局。
动画用 transform/opacity,开启硬件加速。
固定宽高,避免图片/内容导致布局偏移。
用 BFC 隔离渲染区域,减少影响范围。
Q10:什么是布局抖动(Layout Thrashing)?如何避免?
答:
布局抖动:循环中频繁“读取布局属性 + 修改样式”,导致浏览器强制多次重排。
示例:
JavaScriptfor (let i = 0; i < 100; i++) { const h = div.offsetHeight; // 读 div.style.top = h + i + 'px'; // 写 → 每次都触发重排 }避免:
先批量读,再批量写。
使用
requestAnimationFrame分批更新。
Q11:CSS 性能优化要点?
答:
减少选择器层级,避免嵌套过深。
避免通配符、属性选择器慢查询。
关键 CSS 内联,非关键 CSS 异步加载。
用
will-change提示浏览器提前优化(适度使用)。减少昂贵属性:
box-shadow、gradient、filter频繁重绘。
四、JS 运行时优化(执行、内存、事件)
Q12:JS 执行优化手段?
答:
减少全局变量,避免全局查找。
循环优化:缓存长度、避免循环内 DOM 操作、避免复杂计算。
防抖节流处理高频事件(scroll/resize/input)。
避免闭包滥用导致内存泄漏。
耗时逻辑 Web Worker 化。
懒执行:非首屏逻辑延迟到使用时执行。
Q13:常见内存泄漏场景与解决方案?
答:
意外全局变量:未声明变量 → 严格模式、ESLint。
遗忘的定时器/事件监听 → 组件卸载时清除。
闭包引用 → 及时解除引用。
DOM 引用未清理 → 移除 DOM 同时删除引用。
控制台打印 → 生产环境关闭 console。
缓存未限制大小 → LRU 缓存淘汰。
Q14:什么是垃圾回收(GC)?如何减少 GC 压力?
答:
JS 自动 GC,标记清除/分代回收。
减少 GC 压力:
避免频繁创建销毁对象(如循环内创建临时对象)。
复用对象/数组,避免频繁扩容。
长列表用虚拟列表,减少 DOM 与内存占用。
Q15:requestAnimationFrame / requestIdleCallback 区别与使用场景?
答:
requestAnimationFrame:在下次重绘前执行,适合动画、DOM 更新。
requestIdleCallback:浏览器空闲时执行,适合低优先级任务(埋点、日志、预加载)。
五、React 性能优化(高频)
Q16:React 性能优化核心思路?
答:
核心:减少不必要渲染 + 减少渲染耗时 + 减少包体积。
Q17:React 避免重渲染手段?
答:
React.memo缓存组件(浅对比 props)。useCallback缓存函数,避免子组件重新渲染。useMemo缓存计算结果与复杂对象。列表用唯一稳定 key,避免 index。
拆分组件:频繁更新与不更新部分分离。
状态下放:把状态放到真正需要的子组件里。
合理使用 Context:拆分 Context,配合 useMemo 缓存 value。
Q18:React.memo / PureComponent / shouldComponentUpdate 区别?
答:
都是浅对比,避免不必要渲染。
React.memo:函数组件 HOC。PureComponent:类组件,内置shouldComponentUpdate。shouldComponentUpdate:手动控制,可深对比(不推荐)。
Q19:React 长列表优化?
答:
虚拟列表:
react-window/react-virtualized,只渲染可视区域。固定行高,避免动态计算。
懒加载/分页加载,减少一次性渲染量。
组件复用,避免频繁创建销毁。
Q20:React 18 并发特性与性能优化?
答:
自动批处理:所有场景 setState 合并,减少渲染。
useTransition:标记低优先级更新,不阻塞交互。useDeferredValue:延迟非紧急值更新,类似防抖。Suspense 数据获取:更好的加载状态管理,减少抖动。
六、Vue 性能优化(高频)
Q21:Vue 性能优化核心手段?
答:
编译优化:PatchFlag、静态提升、事件监听缓存。
合理使用
v-ifvsv-show:频繁切换用v-show。v-for必须 key,避免 index。组件懒加载:
defineAsyncComponent。长列表:虚拟滚动
vue-virtual-scroller。状态管理优化:拆分 store,避免全局状态滥用。
keep-alive缓存页面,配合include/exclude。非响应式数据用
markRaw/shallowRef减少代理开销。
Q22:Vue3 编译优化(PatchFlag、静态提升)原理?
答:
PatchFlag:编译时给动态节点打标记,更新时只 diff 动态部分。
静态提升:静态节点提升到渲染函数外,只创建一次,复用。
事件缓存:内联事件函数缓存,避免每次渲染创建新函数。
Q23:Vue 中 computed / watch / methods 性能区别?
答:
computed:缓存,依赖不变不重新计算,适合派生状态。
watch:监听变化执行副作用,适合异步/复杂逻辑。
methods:每次渲染都执行,无缓存,适合事件/无缓存逻辑。
七、工程化与构建优化(Webpack/Vite)
Q24:Webpack 性能优化手段?
答:
缩小构建范围:
exclude/include、noParse、cache。多进程:
thread-loader、HappyPack。代码分割:
splitChunks分离公共依赖、路由懒加载。Tree Shaking:ES Module、
sideEffects、生产模式。压缩:
terser-webpack-plugin、css-minimizer-webpack-plugin。CDN 引入:大库用 CDN,不打包。
DLL 预编译:提前编译第三方依赖。
Q25:Vite 为什么比 Webpack 快?
答:
开发模式:
基于 ESBuild 预构建依赖。
浏览器原生 ESM,按需请求,不打包。
热更新只更新修改模块,秒级更新。
生产模式:Rollup 打包,体积更小。
Q26:Tree Shaking 原理与前提?
答:
原理:静态分析 ES Module,删除未使用代码。
前提:
ES Module(import/export)。
生产模式,开启优化。
无副作用(配置
sideEffects)。
八、Electron 桌面端性能优化(专项)
Q27:Electron 启动慢如何优化?
答:
主进程延迟初始化:非必要逻辑放到 ready 后异步执行。
窗口先隐藏,加载完成再 show。
预加载脚本轻量化,只做通信封装。
禁用不必要功能:spellcheck、自动填充等。
依赖裁剪,减小包体积。
Q28:Electron 包体积过大如何优化?
答:
剔除 devDependencies。
ASAR 打包,压缩源码。
按需引入依赖,替换大体积库。
分平台打包,只打目标平台。
考虑 Tauri 替代(更小体积)。
Q29:Electron 渲染卡顿如何优化?
答:
关闭不必要的 webPreferences:webSecurity 按需关闭。
开启硬件加速。
长列表虚拟滚动。
主进程与渲染进程通信避免频繁大数据传输。
避免同步 IPC(sendSync),改用 invoke。
九、综合实战题(面试官最爱)
Q30:你做过哪些性能优化?请按项目讲一个完整案例。
答题结构(STAR):
背景:项目、问题(LCP 超时、白屏、卡顿)。
分析:用 Lighthouse/Performance 定位瓶颈(资源大、长任务、重排)。
方案:
图片 WebP + 懒加载 + 骨架屏。
路由/组件懒加载,代码分割。
防抖节流,长任务拆分。
虚拟列表,减少渲染。
HTTP 缓存 + CDN。
结果:LCP 从 4s → 1.8s,FID 下降 60%,用户留存提升。
Q31:首屏加载慢,你会怎么一步步排查与优化?
答:
看网络:Network 面板看资源大小、加载顺序、TTFB。
看渲染:Lighthouse 看 FCP/LCP/CLS。
看执行:Performance 看长任务、JS 执行耗时。
优化顺序:
图片优化(WebP、懒加载、响应式)。
关键 CSS 内联,非关键异步。
代码分割、懒加载、Tree Shaking。
接口合并、缓存、预加载。
长任务拆分、Web Worker。
Q32:页面滚动卡顿,如何排查与优化?
答:
定位:Performance 看 scroll 事件是否有长任务。
优化:
给 scroll 加防抖/节流。
避免滚动中 DOM 操作、重排。
用 transform 做滚动相关动画。
长列表虚拟滚动。
避免滚动中频繁请求/计算。
十、高频手写题(性能相关)
Q33:手写防抖(debounce)
function debounce(fn, delay = 300) {
let timer = null
return function (...args) {
clearTimeout(timer)
timer = setTimeout(() => fn.apply(this, args), delay)
}
}Q34:手写节流(throttle)
function throttle(fn, interval = 300) {
let last = 0
return function (...args) {
const now = Date.now()
if (now - last >= interval) {
last = now
fn.apply(this, args)
}
}
}Q35:图片懒加载(Intersection Observer)
function lazyLoad() {
const imgs = document.querySelectorAll('img.lazy')
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target
img.src = img.dataset.src
img.classList.remove('lazy')
observer.unobserve(img)
}
})
})
imgs.forEach(img => observer.observe(img))
}复习建议
每天按“加载 → 渲染 → JS → 框架 → 工程化”过一遍。
重点背:LCP/CLS/FID、HTTP 缓存、重排重绘、React/Vue 避免重渲染、Webpack/Vite 优化。
准备 1~2 个真实项目优化案例,带数据,面试最加分。
如果你需要,我可以再给你做一份:
“性能优化面试 10 分钟速记版”(极度精简,适合临考)
或按“每天 30 分钟”给你做一个7 天突击计划。
(注:文档部分内容可能由 AI 生成)