前端老旧项目全面性能优化指南与面试攻略
核心 Web VitalsLCP (Largest Contentful Paint): 最大内容绘制时间FID (First Input Delay): 首次输入延迟CLS (Cumulative Layout Shift): 累积布局偏移其他重要指标浏览器开发者工具Lighthouse 自动化分析WebPageTest 分析加载性能问题运行时性能问题代码分割与懒加载避免阻塞主线程内存优化2.
前端老旧项目全面性能优化指南与面试攻略
目录
项目性能分析与诊断
1. 性能指标了解
核心 Web Vitals
-
LCP (Largest Contentful Paint): 最大内容绘制时间
- 良好: ≤ 2.5s
- 需要改进: 2.5s - 4s
- 差: > 4s
-
FID (First Input Delay): 首次输入延迟
- 良好: ≤ 100ms
- 需要改进: 100ms - 300ms
- 差: > 300ms
-
CLS (Cumulative Layout Shift): 累积布局偏移
- 良好: ≤ 0.1
- 需要改进: 0.1 - 0.25
- 差: > 0.25
其他重要指标
- FCP (First Contentful Paint): 首次内容绘制
- TTI (Time to Interactive): 可交互时间
- TBT (Total Blocking Time): 总阻塞时间
- SI (Speed Index): 速度指数
2. 性能分析工具使用
浏览器开发者工具
// Performance API 分析
const observer = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
console.log('Performance entry:', entry);
});
});
observer.observe({
entryTypes: ['navigation', 'resource', 'paint', 'largest-contentful-paint']
});
// 手动标记关键时间点
performance.mark('component-start');
// ... 组件渲染逻辑
performance.mark('component-end');
performance.measure('component-render', 'component-start', 'component-end');
Lighthouse 自动化分析
// lighthouse-ci.js 配置
module.exports = {
ci: {
collect: {
url: ['http://localhost:3000'],
numberOfRuns: 3,
},
assert: {
assertions: {
'categories:performance': ['warn', { minScore: 0.9 }],
'categories:accessibility': ['error', { minScore: 0.9 }],
},
},
upload: {
target: 'lhci',
serverBaseUrl: 'https://your-lhci-server.com',
},
},
};
WebPageTest 分析
- 多地区测试
- 真实设备测试
- 网络条件模拟
- 详细的瀑布图分析
3. 性能问题诊断清单
加载性能问题
- 资源文件过大(JS、CSS、图片)
- 关键资源未优先加载
- 阻塞渲染的资源
- 网络请求过多
- 缓存策略不合理
运行时性能问题
- JavaScript 执行时间过长
- 频繁的 DOM 操作
- 内存泄漏
- 未优化的事件监听器
- 重复的计算或渲染
代码层面优化
1. JavaScript 优化
代码分割与懒加载
// 路由级别的代码分割
const routes = [
{
path: '/home',
component: () => import('./views/Home.vue')
},
{
path: '/profile',
component: () => import('./views/Profile.vue')
}
];
// 组件级别的懒加载
const LazyComponent = React.lazy(() => import('./LazyComponent'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
);
}
避免阻塞主线程
// 使用 requestIdleCallback 进行任务调度
function performHeavyTask(data) {
const chunks = chunkArray(data, 100);
function processChunk(index = 0) {
if (index >= chunks.length) return;
requestIdleCallback((deadline) => {
while (deadline.timeRemaining() > 0 && index < chunks.length) {
processDataChunk(chunks[index]);
index++;
}
if (index < chunks.length) {
processChunk(index);
}
});
}
processChunk();
}
// Web Workers 处理CPU密集型任务
// main.js
const worker = new Worker('calculation-worker.js');
worker.postMessage({ data: largeDataSet });
worker.onmessage = (e) => {
console.log('计算结果:', e.data);
};
// calculation-worker.js
self.onmessage = function(e) {
const result = heavyCalculation(e.data);
self.postMessage(result);
};
内存优化
// 防止内存泄漏
class ComponentManager {
constructor() {
this.timers = new Set();
this.observers = new Set();
this.eventListeners = new Map();
}
addTimer(id) {
this.timers.add(id);
}
addObserver(observer) {
this.observers.add(observer);
}
addEventListener(element, event, handler) {
element.addEventListener(event, handler);
if (!this.eventListeners.has(element)) {
this.eventListeners.set(element, []);
}
this.eventListeners.get(element).push({ event, handler });
}
cleanup() {
// 清理定时器
this.timers.forEach(id => clearInterval(id));
this.timers.clear();
// 清理观察者
this.observers.forEach(observer => observer.disconnect());
this.observers.clear();
// 清理事件监听器
this.eventListeners.forEach((events, element) => {
events.forEach(({ event, handler }) => {
element.removeEventListener(event, handler);
});
});
this.eventListeners.clear();
}
}
2. CSS 优化
关键 CSS 提取
// 使用 critical 包提取关键CSS
const critical = require('critical');
critical.generate({
inline: true,
base: 'dist/',
src: 'index.html',
target: {
css: 'critical.css',
html: 'index-critical.html'
},
width: 1300,
height: 900,
minify: true
});
CSS 优化技巧
/* 避免深层嵌套和复杂选择器 */
/* 不好的做法 */
.header .nav .menu li a:hover {
color: blue;
}
/* 好的做法 */
.nav-link:hover {
color: blue;
}
/* 使用 CSS containment 优化渲染性能 */
.card {
contain: layout style paint;
}
/* 使用 will-change 提示浏览器优化 */
.animated-element {
will-change: transform;
}
.animated-element.done {
will-change: auto; /* 动画完成后移除 */
}
/* 使用 CSS 变量减少重复计算 */
:root {
--primary-color: #007bff;
--border-radius: 4px;
--shadow: 0 2px 4px rgba(0,0,0,0.1);
}
CSS 加载优化
<!-- 预加载关键字体 -->
<link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>
<!-- 异步加载非关键CSS -->
<link rel="preload" href="/css/non-critical.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/css/non-critical.css"></noscript>
资源加载优化
1. 图片优化
现代图片格式
<!-- 使用 picture 元素支持多种格式 -->
<picture>
<source srcset="image.avif" type="image/avif">
<source srcset="image.webp" type="image/webp">
<img src="image.jpg" alt="描述" loading="lazy">
</picture>
响应式图片
<!-- 基于视口宽度的响应式图片 -->
<img src="small.jpg"
srcset="small.jpg 480w, medium.jpg 800w, large.jpg 1200w"
sizes="(max-width: 480px) 100vw, (max-width: 800px) 50vw, 33vw"
alt="响应式图片">
图片懒加载实现
// 使用 Intersection Observer 实现懒加载
class LazyImageLoader {
constructor() {
this.imageObserver = new IntersectionObserver(
this.onImageIntersection.bind(this),
{ rootMargin: '50px' }
);
this.init();
}
init() {
const lazyImages = document.querySelectorAll('img[data-src]');
lazyImages.forEach(img => this.imageObserver.observe(img));
}
onImageIntersection(entries) {
entries.forEach(entry => {
if (entry.isIntersecting) {
this.loadImage(entry.target);
this.imageObserver.unobserve(entry.target);
}
});
}
loadImage(img) {
img.src = img.dataset.src;
img.onload = () => img.classList.add('loaded');
img.onerror = () => img.classList.add('error');
}
}
new LazyImageLoader();
2. 字体优化
字体加载策略
/* 字体显示策略 */
@font-face {
font-family: 'CustomFont';
src: url('/fonts/custom.woff2') format('woff2');
font-display: swap; /* 立即显示后备字体 */
}
/* 字体预加载 */
<link rel="preload" href="/fonts/critical.woff2" as="font" type="font/woff2" crossorigin>
字体子集化
// 使用 fonttools 进行字体子集化
const fontSubset = require('font-subset');
fontSubset({
font: 'source-font.ttf',
text: '需要的文字内容',
output: 'subset-font.woff2'
});
3. 资源预加载策略
<!-- DNS 预解析 -->
<link rel="dns-prefetch" href="//api.example.com">
<!-- 预连接 -->
<link rel="preconnect" href="https://fonts.googleapis.com" crossorigin>
<!-- 资源预加载 -->
<link rel="preload" href="/critical.css" as="style">
<link rel="preload" href="/hero-image.jpg" as="image">
<!-- 预获取下一页资源 -->
<link rel="prefetch" href="/next-page.html">
<!-- 模块预加载 -->
<link rel="modulepreload" href="/modules/app.js">
运行时性能优化
1. DOM 操作优化
批量 DOM 操作
// 使用 DocumentFragment 减少重排重绘
function batchUpdateDOM(items) {
const fragment = document.createDocumentFragment();
items.forEach(item => {
const element = document.createElement('div');
element.textContent = item.text;
element.className = item.className;
fragment.appendChild(element);
});
// 一次性插入所有元素
document.getElementById('container').appendChild(fragment);
}
// 使用 requestAnimationFrame 优化动画
function animateElement(element, from, to, duration) {
const start = performance.now();
function update(currentTime) {
const elapsed = currentTime - start;
const progress = Math.min(elapsed / duration, 1);
const current = from + (to - from) * progress;
element.style.transform = `translateX(${current}px)`;
if (progress < 1) {
requestAnimationFrame(update);
}
}
requestAnimationFrame(update);
}
虚拟滚动实现
class VirtualScroller {
constructor(container, itemHeight, items) {
this.container = container;
this.itemHeight = itemHeight;
this.items = items;
this.visibleCount = Math.ceil(container.clientHeight / itemHeight) + 2;
this.startIndex = 0;
this.init();
}
init() {
this.container.style.height = `${this.items.length * this.itemHeight}px`;
this.container.addEventListener('scroll', this.onScroll.bind(this));
this.render();
}
onScroll() {
const scrollTop = this.container.scrollTop;
const newStartIndex = Math.floor(scrollTop / this.itemHeight);
if (newStartIndex !== this.startIndex) {
this.startIndex = newStartIndex;
this.render();
}
}
render() {
const endIndex = Math.min(
this.startIndex + this.visibleCount,
this.items.length
);
const visibleItems = this.items.slice(this.startIndex, endIndex);
this.container.innerHTML = visibleItems.map((item, index) => `
<div class="item" style="
position: absolute;
top: ${(this.startIndex + index) * this.itemHeight}px;
height: ${this.itemHeight}px;
">
${item.content}
</div>
`).join('');
}
}
2. 事件优化
事件委托
// 使用事件委托减少事件监听器数量
class EventDelegator {
constructor(container) {
this.container = container;
this.handlers = new Map();
this.container.addEventListener('click', this.handleClick.bind(this));
}
register(selector, handler) {
if (!this.handlers.has(selector)) {
this.handlers.set(selector, []);
}
this.handlers.get(selector).push(handler);
}
handleClick(event) {
this.handlers.forEach((handlers, selector) => {
if (event.target.matches(selector)) {
handlers.forEach(handler => handler(event));
}
});
}
}
// 使用示例
const delegator = new EventDelegator(document.body);
delegator.register('.button', (e) => console.log('Button clicked'));
delegator.register('.link', (e) => console.log('Link clicked'));
防抖和节流
// 防抖函数
function debounce(func, wait, immediate = false) {
let timeout;
return function executedFunction(...args) {
const later = () => {
timeout = null;
if (!immediate) func.apply(this, args);
};
const callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(this, args);
};
}
// 节流函数
function throttle(func, limit) {
let inThrottle;
return function(...args) {
if (!inThrottle) {
func.apply(this, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
// 使用示例
const debouncedSearch = debounce((query) => {
// 执行搜索
}, 300);
const throttledScroll = throttle(() => {
// 处理滚动
}, 100);
window.addEventListener('scroll', throttledScroll);
网络请求优化
1. HTTP 优化
请求合并与缓存
// 请求缓存管理器
class RequestCacheManager {
constructor() {
this.cache = new Map();
this.pendingRequests = new Map();
}
async get(url, options = {}) {
const cacheKey = this.getCacheKey(url, options);
// 检查缓存
if (this.cache.has(cacheKey)) {
const cached = this.cache.get(cacheKey);
if (!this.isExpired(cached)) {
return cached.data;
}
}
// 检查是否有pending请求
if (this.pendingRequests.has(cacheKey)) {
return this.pendingRequests.get(cacheKey);
}
// 发起新请求
const request = this.makeRequest(url, options);
this.pendingRequests.set(cacheKey, request);
try {
const data = await request;
this.cache.set(cacheKey, {
data,
timestamp: Date.now(),
ttl: options.ttl || 60000 // 默认1分钟
});
return data;
} finally {
this.pendingRequests.delete(cacheKey);
}
}
getCacheKey(url, options) {
return `${url}:${JSON.stringify(options)}`;
}
isExpired(cached) {
return Date.now() - cached.timestamp > cached.ttl;
}
async makeRequest(url, options) {
const response = await fetch(url, options);
return response.json();
}
}
批量请求优化
// 请求批处理器
class BatchRequestProcessor {
constructor(batchSize = 10, delay = 100) {
this.batchSize = batchSize;
this.delay = delay;
this.queue = [];
this.processing = false;
}
add(request) {
return new Promise((resolve, reject) => {
this.queue.push({ request, resolve, reject });
this.process();
});
}
async process() {
if (this.processing || this.queue.length === 0) return;
this.processing = true;
while (this.queue.length > 0) {
const batch = this.queue.splice(0, this.batchSize);
try {
const promises = batch.map(({ request }) => request());
const results = await Promise.allSettled(promises);
results.forEach((result, index) => {
const { resolve, reject } = batch[index];
if (result.status === 'fulfilled') {
resolve(result.value);
} else {
reject(result.reason);
}
});
} catch (error) {
batch.forEach(({ reject }) => reject(error));
}
// 批次间延迟
if (this.queue.length > 0) {
await new Promise(resolve => setTimeout(resolve, this.delay));
}
}
this.processing = false;
}
}
2. 数据预加载
智能预加载策略
// 路由预加载器
class RoutePreloader {
constructor() {
this.preloadedRoutes = new Set();
this.observer = new IntersectionObserver(
this.onLinkVisible.bind(this),
{ rootMargin: '100px' }
);
this.init();
}
init() {
// 监听所有路由链接
const links = document.querySelectorAll('a[href^="/"]');
links.forEach(link => this.observer.observe(link));
// 鼠标悬停预加载
document.addEventListener('mouseover', this.onLinkHover.bind(this));
}
onLinkVisible(entries) {
entries.forEach(entry => {
if (entry.isIntersecting) {
const href = entry.target.getAttribute('href');
this.preloadRoute(href);
}
});
}
onLinkHover(event) {
if (event.target.tagName === 'A' && event.target.href) {
const href = new URL(event.target.href).pathname;
this.preloadRoute(href);
}
}
async preloadRoute(href) {
if (this.preloadedRoutes.has(href)) return;
this.preloadedRoutes.add(href);
try {
// 预加载路由组件
const module = await import(/* webpackChunkName: "[request]" */ `./views${href}`);
console.log(`预加载路由: ${href}`);
} catch (error) {
console.warn(`预加载路由失败: ${href}`, error);
this.preloadedRoutes.delete(href);
}
}
}
构建与部署优化
1. Webpack 构建优化
配置优化示例
// webpack.config.js
const path = require('path');
const TerserPlugin = require('terser-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
module.exports = {
mode: 'production',
// 入口优化
entry: {
app: './src/main.js',
vendor: ['react', 'react-dom', 'lodash'] // 提取第三方库
},
// 输出优化
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[contenthash:8].js',
chunkFilename: '[name].[contenthash:8].chunk.js',
clean: true
},
// 优化配置
optimization: {
// 代码分割
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
priority: 10
},
common: {
name: 'common',
minChunks: 2,
chunks: 'all',
priority: 5
}
}
},
// 压缩优化
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true, // 移除console
drop_debugger: true // 移除debugger
}
},
parallel: true // 并行压缩
})
],
// 运行时代码提取
runtimeChunk: 'single'
},
// 插件配置
plugins: [
// Gzip压缩
new CompressionPlugin({
algorithm: 'gzip',
test: /\.(js|css|html|svg)$/,
threshold: 8192,
minRatio: 0.8
}),
// 包分析
process.env.ANALYZE && new BundleAnalyzerPlugin()
].filter(Boolean),
// 模块解析优化
resolve: {
alias: {
'@': path.resolve(__dirname, 'src')
},
extensions: ['.js', '.jsx', '.ts', '.tsx'],
modules: ['node_modules'] // 限制模块查找范围
},
// 外部化依赖
externals: {
'react': 'React',
'react-dom': 'ReactDOM'
}
};
2. 现代构建工具优化
Vite 配置优化
// vite.config.js
import { defineConfig } from 'vite';
import { resolve } from 'path';
export default defineConfig({
// 构建优化
build: {
target: 'es2015',
minify: 'terser',
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true
}
},
// 代码分割
rollupOptions: {
output: {
manualChunks: {
vendor: ['react', 'react-dom'],
utils: ['lodash', 'dayjs']
}
}
},
// 资源大小限制
chunkSizeWarningLimit: 1000
},
// 开发服务器优化
server: {
hmr: {
overlay: false // 关闭错误遮罩层
}
},
// 插件配置
plugins: [
// ... 插件配置
],
// 依赖预构建
optimizeDeps: {
include: ['react', 'react-dom'],
exclude: ['@vueuse/core']
}
});
3. CDN 与缓存策略
缓存策略配置
# nginx 配置示例
server {
listen 80;
server_name example.com;
# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
add_header Vary "Accept-Encoding";
# 启用 gzip
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
}
# HTML 文件缓存策略
location ~* \.(html|htm)$ {
expires 1h;
add_header Cache-Control "public, must-revalidate";
}
# API 缓存
location /api/ {
proxy_pass http://backend;
proxy_cache my_cache;
proxy_cache_valid 200 5m;
proxy_cache_key $request_uri;
}
}
监控与持续优化
1. 性能监控实现
Real User Monitoring (RUM)
// 性能监控类
class PerformanceMonitor {
constructor(apiUrl) {
this.apiUrl = apiUrl;
this.metrics = {};
this.init();
}
init() {
// 监听页面加载完成
window.addEventListener('load', () => {
this.collectPageMetrics();
});
// 监听 CLS
this.observeCLS();
// 监听 LCP
this.observeLCP();
// 监听 FID
this.observeFID();
// 定期发送数据
setInterval(() => this.sendMetrics(), 30000);
}
collectPageMetrics() {
const navigation = performance.getEntriesByType('navigation')[0];
this.metrics = {
...this.metrics,
dns: navigation.domainLookupEnd - navigation.domainLookupStart,
tcp: navigation.connectEnd - navigation.connectStart,
request: navigation.responseStart - navigation.requestStart,
response: navigation.responseEnd - navigation.responseStart,
dom: navigation.domContentLoadedEventEnd - navigation.domContentLoadedEventStart,
load: navigation.loadEventEnd - navigation.loadEventStart,
fcp: this.getFCP(),
ttfb: navigation.responseStart - navigation.requestStart
};
}
observeCLS() {
let clsValue = 0;
let clsEntries = [];
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (!entry.hadRecentInput) {
clsValue += entry.value;
clsEntries.push(entry);
}
}
this.metrics.cls = clsValue;
});
observer.observe({ type: 'layout-shift', buffered: true });
}
observeLCP() {
const observer = new PerformanceObserver((list) => {
const entries = list.getEntries();
const lastEntry = entries[entries.length - 1];
this.metrics.lcp = lastEntry.startTime;
});
observer.observe({ type: 'largest-contentful-paint', buffered: true });
}
observeFID() {
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
this.metrics.fid = entry.processingStart - entry.startTime;
}
});
observer.observe({ type: 'first-input', buffered: true });
}
getFCP() {
const fcpEntry = performance.getEntriesByName('first-contentful-paint')[0];
return fcpEntry ? fcpEntry.startTime : null;
}
async sendMetrics() {
if (Object.keys(this.metrics).length === 0) return;
try {
await fetch(this.apiUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
url: location.href,
userAgent: navigator.userAgent,
timestamp: Date.now(),
metrics: this.metrics
})
});
} catch (error) {
console.error('发送监控数据失败:', error);
}
}
}
// 初始化监控
new PerformanceMonitor('/api/metrics');
2. 错误监控
错误收集与上报
class ErrorMonitor {
constructor(apiUrl) {
this.apiUrl = apiUrl;
this.errorQueue = [];
this.maxQueueSize = 10;
this.init();
}
init() {
// JavaScript 错误监听
window.addEventListener('error', this.handleError.bind(this));
// Promise 未捕获错误
window.addEventListener('unhandledrejection', this.handlePromiseError.bind(this));
// 资源加载错误
window.addEventListener('error', this.handleResourceError.bind(this), true);
// 定期发送错误
setInterval(() => this.flushErrors(), 10000);
}
handleError(event) {
this.addError({
type: 'javascript',
message: event.message,
filename: event.filename,
lineno: event.lineno,
colno: event.colno,
stack: event.error?.stack,
timestamp: Date.now()
});
}
handlePromiseError(event) {
this.addError({
type: 'promise',
message: event.reason.toString(),
stack: event.reason.stack,
timestamp: Date.now()
});
}
handleResourceError(event) {
if (event.target !== window) {
this.addError({
type: 'resource',
message: `Failed to load ${event.target.tagName}`,
source: event.target.src || event.target.href,
timestamp: Date.now()
});
}
}
addError(error) {
this.errorQueue.push(error);
if (this.errorQueue.length >= this.maxQueueSize) {
this.flushErrors();
}
}
async flushErrors() {
if (this.errorQueue.length === 0) return;
const errors = [...this.errorQueue];
this.errorQueue = [];
try {
await fetch(this.apiUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
url: location.href,
userAgent: navigator.userAgent,
errors
})
});
} catch (error) {
// 发送失败,重新加入队列
this.errorQueue.unshift(...errors);
}
}
}
面试回答技巧
1. 回答框架
STAR 方法
- Situation: 描述项目背景和遇到的性能问题
- Task: 说明你的任务和目标
- Action: 详细描述你采取的优化措施
- Result: 量化优化结果和效果
2. 常见面试问题及回答要点
问题1: 如何分析老旧项目的性能问题?
回答要点:
1. 性能指标分析
- 使用 Lighthouse 进行综合评估
- Chrome DevTools 分析加载时间线
- 监控 Core Web Vitals 指标
2. 代码质量审查
- 分析 bundle 大小和组成
- 检查无用代码和重复依赖
- 评估代码分割情况
3. 网络性能分析
- 检查资源加载策略
- 分析缓存配置
- 评估 CDN 使用情况
4. 运行时性能分析
- 使用 Performance 面板分析主线程阻塞
- 检查内存使用和泄漏
- 分析重排重绘频率
问题2: 具体实施了哪些优化措施?
回答示例:
我负责的项目是一个电商后台管理系统,页面加载时间超过8秒,用户体验很差。
优化措施:
1. 构建优化 (40% 性能提升)
- 实施代码分割,将第三方库单独打包
- 启用 Tree Shaking 删除无用代码
- 配置 Gzip 压缩,资源大小减少60%
2. 资源优化 (30% 性能提升)
- 图片格式现代化,使用 WebP
- 实施图片懒加载
- 字体预加载和子集化
3. 代码优化 (20% 性能提升)
- 实施虚拟滚动解决长列表性能问题
- 使用 React.memo 和 useMemo 减少不必要渲染
- 优化事件处理,使用防抖节流
4. 缓存策略 (10% 性能提升)
- 配置合理的 HTTP 缓存策略
- 实施接口缓存和预加载
结果:页面加载时间从8秒降到2.5秒,Lighthouse 分数从30分提升到85分。
问题3: 如何保证优化效果的持续性?
回答要点:
1. 性能监控体系
- 部署 RUM 监控收集真实用户数据
- 设置性能预警阈值
- 定期生成性能报告
2. 开发流程集成
- CI/CD 中集成 Lighthouse 检查
- Bundle 分析报告
- 性能回归测试
3. 团队规范建立
- 制定性能开发规范
- 代码审查中关注性能
- 定期技术分享和培训
4. 持续优化机制
- 月度性能回顾会议
- 新技术调研和应用
- 用户反馈收集和处理
3. 面试加分技巧
展示技术深度
- 能够解释优化原理,不只是列举方法
- 提及新技术和最佳实践的应用
- 展示对浏览器工作原理的理解
展示业务思维
- 将技术优化与业务价值关联
- 提及用户体验改善和转化率提升
- 展示成本效益分析能力
展示团队协作
- 说明如何推动团队采用新的优化方案
- 分享知识传递和培训经验
- 展示跨部门沟通协调能力
实战案例分析
案例1: 电商网站首页优化
优化前状况:
- 首屏加载时间: 6.8秒
- Lighthouse 分数: 32分
- 资源总大小: 3.2MB
- JavaScript 执行时间: 2.1秒
优化措施:
- 关键资源优化
// 首屏关键CSS内联
const criticalCSS = `
.header { height: 60px; background: #fff; }
.hero { height: 400px; background: #f5f5f5; }
`;
// 非关键CSS异步加载
const loadCSS = (href) => {
const link = document.createElement('link');
link.rel = 'preload';
link.as = 'style';
link.href = href;
link.onload = () => link.rel = 'stylesheet';
document.head.appendChild(link);
};
- 图片优化
<!-- 首屏轮播图优化 -->
<picture>
<source srcset="hero-mobile.webp" media="(max-width: 768px)" type="image/webp">
<source srcset="hero-desktop.webp" type="image/webp">
<img src="hero-desktop.jpg" alt="首页轮播" loading="eager">
</picture>
- JavaScript 优化
// 路由懒加载
const routes = [
{
path: '/product/:id',
component: () => import(/* webpackChunkName: "product" */ './Product.vue')
}
];
// 第三方脚本延迟加载
const loadScript = (src, defer = true) => {
const script = document.createElement('script');
script.src = src;
script.defer = defer;
document.head.appendChild(script);
};
// 页面加载完成后加载非关键脚本
window.addEventListener('load', () => {
loadScript('/js/analytics.js');
loadScript('/js/chat-widget.js');
});
优化结果:
- 首屏加载时间: 2.1秒 (提升69%)
- Lighthouse 分数: 89分 (提升178%)
- 资源总大小: 1.8MB (减少44%)
- 用户转化率提升15%
案例2: 后台管理系统优化
优化前问题:
- 列表页渲染1000条数据卡顿严重
- 内存占用持续增长,存在泄漏
- 频繁的接口请求导致服务器压力大
优化方案:
- 虚拟滚动实现
<template>
<div class="virtual-list" ref="container" @scroll="onScroll">
<div class="virtual-list-phantom" :style="{ height: totalHeight + 'px' }"></div>
<div class="virtual-list-content" :style="getContentStyle()">
<div
v-for="item in visibleItems"
:key="item.id"
class="virtual-list-item"
:style="{ height: itemHeight + 'px' }"
>
<slot :item="item"></slot>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
items: Array,
itemHeight: { type: Number, default: 50 }
},
data() {
return {
startIndex: 0,
endIndex: 0,
containerHeight: 0
};
},
computed: {
totalHeight() {
return this.items.length * this.itemHeight;
},
visibleCount() {
return Math.ceil(this.containerHeight / this.itemHeight) + 2;
},
visibleItems() {
return this.items.slice(this.startIndex, this.endIndex);
}
},
methods: {
onScroll() {
const scrollTop = this.$refs.container.scrollTop;
this.startIndex = Math.floor(scrollTop / this.itemHeight);
this.endIndex = this.startIndex + this.visibleCount;
},
getContentStyle() {
return {
transform: `translateY(${this.startIndex * this.itemHeight}px)`
};
}
}
};
</script>
- 内存泄漏修复
// 组件清理机制
export default {
data() {
return {
timers: [],
observers: [],
subscriptions: []
};
},
methods: {
addTimer(id) {
this.timers.push(id);
},
addObserver(observer) {
this.observers.push(observer);
},
addSubscription(subscription) {
this.subscriptions.push(subscription);
}
},
beforeDestroy() {
// 清理定时器
this.timers.forEach(clearInterval);
// 清理观察者
this.observers.forEach(observer => observer.disconnect());
// 清理订阅
this.subscriptions.forEach(sub => sub.unsubscribe());
}
};
- 接口请求优化
// 请求去重和缓存
class APIManager {
constructor() {
this.cache = new Map();
this.pendingRequests = new Map();
}
async request(url, options = {}) {
const key = `${url}:${JSON.stringify(options)}`;
// 检查缓存
if (this.cache.has(key)) {
const cached = this.cache.get(key);
if (Date.now() - cached.timestamp < 30000) {
return cached.data;
}
}
// 防止重复请求
if (this.pendingRequests.has(key)) {
return this.pendingRequests.get(key);
}
const request = fetch(url, options).then(res => res.json());
this.pendingRequests.set(key, request);
try {
const data = await request;
this.cache.set(key, { data, timestamp: Date.now() });
return data;
} finally {
this.pendingRequests.delete(key);
}
}
}
优化结果:
- 列表渲染性能提升90%,支持10万条数据流畅滚动
- 内存使用稳定,无泄漏现象
- 接口请求减少70%,服务器响应时间提升50%
总结
老旧项目性能优化是一个系统工程,需要从分析、优化、监控三个维度进行全面考虑:
关键成功因素
- 全面的性能分析 - 使用合适的工具找出真正的性能瓶颈
- 分层次的优化策略 - 从构建到运行时的全链路优化
- 持续的监控体系 - 确保优化效果的可持续性
- 团队协作和知识传承 - 让优化成果在团队中延续
面试要点
- 体现技术深度和实战经验
- 强调业务价值和用户体验改善
- 展示系统思维和持续改进能力
- 准备具体的数据和案例支撑
性能优化不仅是技术问题,更是工程问题。在面试中展现你的全面思考能力,会让你在众多候选人中脱颖而出。
更多推荐
所有评论(0)