性能优化面试题
基础概念
前端性能优化的目标是什么?
目标:
- 减少加载时间:首屏加载时间、可交互时间
- 提升运行时性能:减少卡顿、提升流畅度
- 优化资源使用:减少带宽、内存占用
- 提升用户体验:快速响应、流畅交互
前端性能优化的方向有哪些?
主要方向:
- 网络层面:减少请求数、压缩资源、使用 CDN
- 渲染层面:减少重排重绘、优化渲染路径
- 代码层面:代码分割、Tree Shaking、懒加载
- 资源层面:图片优化、字体优化、资源预加载
- 缓存层面:HTTP 缓存、Service Worker、应用缓存
加载性能
如何优化首屏加载时间?
优化策略:
- 代码分割:路由懒加载、组件懒加载
- 资源压缩:Gzip、Brotli、代码压缩
- 图片优化:WebP 格式、懒加载、响应式图片
- 关键资源内联:关键 CSS、关键 JS
- 预加载:DNS 预解析、资源预加载
- CDN 加速:使用 CDN 分发静态资源
- HTTP/2:多路复用、服务器推送
什么是关键渲染路径?如何优化?
关键渲染路径:
- HTML → DOM
- CSS → CSSOM
- DOM + CSSOM → Render Tree
- Render Tree → Layout
- Layout → Paint
优化方法:
- 减少关键资源数量
- 减少关键资源大小
- 缩短关键渲染路径长度
- 内联关键 CSS
- 延迟非关键 CSS
如何实现代码分割?
方式:
- 路由分割:
import()动态导入 - 组件分割:React.lazy、Vue 异步组件
- 第三方库分割:单独打包 vendor
- 公共代码提取:SplitChunksPlugin
// 路由懒加载
const Home = () => import('./views/Home.vue');
// 组件懒加载
const HeavyComponent = lazy(() => import('./components/HeavyComponent'));
// 动态导入
if (condition) {
import('./module').then(module => {
// 使用模块
});
}
图片优化的方法有哪些?
优化方法:
- 格式选择:WebP、AVIF、适当使用 PNG/JPEG
- 图片压缩:TinyPNG、ImageOptim
- 懒加载:
loading="lazy"、Intersection Observer - 响应式图片:
srcset、sizes - 雪碧图:合并小图标
- Base64:小图片内联
- CDN 压缩:使用 CDN 自动压缩
运行时性能
什么是重排和重绘?如何减少?
重排(Reflow):
- 改变元素尺寸、位置、布局
- 触发条件:修改宽高、位置、字体大小等
重绘(Repaint):
- 改变元素外观,不影响布局
- 触发条件:修改颜色、背景、边框等
减少方法:
- 使用
transform和opacity(触发合成层) - 批量 DOM 操作(DocumentFragment)
- 避免频繁读取布局属性
- 使用
will-change提示浏览器 - 使用虚拟滚动处理长列表
防抖和节流的区别?应用场景?
防抖(Debounce):
- 事件触发后等待一段时间执行,期间再次触发则重新计时
- 应用:搜索输入、窗口 resize
节流(Throttle):
- 固定时间间隔执行一次
- 应用:滚动事件、鼠标移动
// 防抖
function debounce(func, wait) {
let timeout;
return function(...args) {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), wait);
};
}
// 节流
function throttle(func, limit) {
let inThrottle;
return function(...args) {
if (!inThrottle) {
func.apply(this, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
什么是虚拟滚动?如何实现?
虚拟滚动:
- 只渲染可见区域的列表项
- 适用于长列表场景
实现思路:
- 计算可见区域高度
- 计算可见项数量
- 只渲染可见项
- 滚动时更新可见项范围
class VirtualScroll {
constructor(container, items, itemHeight) {
this.container = container;
this.items = items;
this.itemHeight = itemHeight;
this.visibleCount = Math.ceil(container.clientHeight / itemHeight);
}
render() {
const startIndex = Math.floor(this.container.scrollTop / this.itemHeight);
const endIndex = startIndex + this.visibleCount;
const visibleItems = this.items.slice(startIndex, endIndex);
// 渲染可见项
}
}
缓存策略
HTTP 缓存有哪些类型?
强缓存:
Cache-Control:max-age、public、privateExpires:过期时间
协商缓存:
ETag/If-None-MatchLast-Modified/If-Modified-Since
如何选择合适的缓存策略?
静态资源:
Cache-Control: public, max-age=31536000, immutable
HTML:
Cache-Control: no-cache
API:
Cache-Control: private, max-age=300
Service Worker 缓存策略有哪些?
Cache First: 缓存优先,适合静态资源 Network First: 网络优先,适合动态内容 Stale While Revalidate: 先返回缓存,后台更新 Network Only: 只使用网络 Cache Only: 只使用缓存
性能指标
Web Vitals 包含哪些指标?
Core Web Vitals:
- LCP (Largest Contentful Paint):最大内容绘制,< 2.5s
- FID (First Input Delay):首次输入延迟,< 100ms
- CLS (Cumulative Layout Shift):累积布局偏移,< 0.1
其他指标:
- FCP (First Contentful Paint)
- TTI (Time to Interactive)
- TBT (Total Blocking Time)
如何测量页面性能?
Performance API:
const perfData = window.performance.timing;
const pageLoadTime = perfData.loadEventEnd - perfData.navigationStart;
Performance Observer:
new PerformanceObserver((list) => {
const entries = list.getEntries();
// 处理性能指标
}).observe({ entryTypes: ['largest-contentful-paint'] });
Lighthouse:
- Chrome DevTools 内置
- 自动化性能测试
- 提供优化建议
优化实践
如何优化首屏加载?
策略:
- 代码分割和懒加载
- 关键 CSS 内联
- 图片懒加载和优化
- 使用骨架屏
- 资源预加载
- CDN 加速
- 启用 Gzip 压缩
如何优化长列表性能?
方法:
- 虚拟滚动:只渲染可见项
- 分页加载:分批加载数据
- 防抖节流:优化滚动事件
- 使用 key:React/Vue 列表 key 优化
- 避免内联样式:减少重排
如何优化图片加载?
优化:
- 选择合适的格式(WebP、AVIF)
- 图片压缩
- 懒加载
- 响应式图片(srcset)
- CDN 加速
- 预加载关键图片
如何优化动画性能?
优化:
- 使用
transform和opacity(GPU 加速) - 避免触发重排的属性
- 使用
will-change提示浏览器 - 使用
requestAnimationFrame - 减少动画复杂度
/* ✅ 好:GPU 加速 */
.element {
transform: translateX(100px);
opacity: 0.5;
}
/* ❌ 不好:触发重排 */
.element {
left: 100px;
top: 100px;
}
工具和监控
常用的性能分析工具有哪些?
浏览器工具:
- Chrome DevTools Performance
- Lighthouse
- Network 面板
- Memory 面板
在线工具:
- WebPageTest
- GTmetrix
- Pingdom
监控工具:
- Google Analytics
- Sentry
- 自定义性能监控
如何实现性能监控?
关键指标监控:
// LCP
new PerformanceObserver((list) => {
const entries = list.getEntries();
const lastEntry = entries[entries.length - 1];
// 上报 LCP
reportMetric('LCP', lastEntry.renderTime);
}).observe({ entryTypes: ['largest-contentful-paint'] });
// FID
new PerformanceObserver((list) => {
list.getEntries().forEach(entry => {
// 上报 FID
reportMetric('FID', entry.processingStart - entry.startTime);
});
}).observe({ entryTypes: ['first-input'] });
最佳实践
性能优化的优先级是什么?
优先级:
- 首屏加载:影响用户体验最关键
- 运行时性能:保证交互流畅
- 资源优化:减少带宽和内存
- 缓存策略:提升重复访问体验
性能优化需要注意什么?
注意事项:
- 不要过度优化
- 平衡性能和可维护性
- 关注实际用户体验
- 持续监控和优化
- 考虑不同设备和网络环境