一、性能指标与监控
1.1 核心Web指标(Core Web Vitals)
// 监控核心Web指标
class WebVitalsMonitor {
async monitor() {
// LCP (Largest Contentful Paint)
const lcp = await this.measureLCP();
// FID (First Input Delay)
const fid = await this.measureFID();
// CLS (Cumulative Layout Shift)
const cls = await this.measureCLS();
return { lcp, fid, cls };
}
measureLCP() {
return new Promise((resolve) => {
const observer = new PerformanceObserver((entryList) => {
const entries = entryList.getEntries();
const lastEntry = entries[entries.length - 1];
resolve(lastEntry.startTime);
});
observer.observe({ type: 'largest-contentful-paint', buffered: true });
});
}
}
1.2 性能监控工具
// 自定义性能监控
class PerformanceMonitor {
constructor() {
this.metrics = new Map();
this.startTime = performance.now();
}
mark(name) {
performance.mark(name);
}
measure(name, startMark, endMark) {
performance.measure(name, startMark, endMark);
const measures = performance.getEntriesByName(name);
this.metrics.set(name, measures[measures.length - 1]);
}
report() {
const report = {
timing: performance.timing,
navigation: performance.getEntriesByType('navigation')[0],
resources: performance.getEntriesByType('resource'),
metrics: Object.fromEntries(this.metrics)
};
// 发送到监控系统
this.sendToAnalytics(report);
return report;
}
}
二、网络优化
2.1 HTTP/2与HTTP/3
# Nginx HTTP/2配置
server {
listen 443 ssl http2;
server_name example.com;
# HTTP/2优化
http2_push_preload on;
http2_max_concurrent_streams 100;
http2_streams_index_size 32;
http2_recv_timeout 30s;
# 资源推送
location = /index.html {
http2_push /style.css;
http2_push /app.js;
http2_push /logo.png;
}
}
2.2 资源加载优化
<!-- 资源加载优化 -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<!-- DNS预连接 -->
<link rel="dns-prefetch" href="https://cdn.example.com">
<link rel="preconnect" href="https://cdn.example.com" crossorigin>
<!-- 预加载关键资源 -->
<link rel="preload" href="/critical.css" as="style">
<link rel="preload" href="/critical.js" as="script">
<link rel="preload" href="/hero-image.jpg" as="image" type="image/jpeg">
<!-- 预获取非关键资源 -->
<link rel="prefetch" href="/next-page.css" as="style">
<link rel="prefetch" href="/next-page.js" as="script">
<!-- 延迟加载 -->
<script>
// 延迟加载非关键脚本
window.addEventListener('load', function() {
const script = document.createElement('script');
script.src = '/non-critical.js';
script.async = true;
document.body.appendChild(script);
});
</script>
</head>
</html>
三、渲染优化
3.1 关键渲染路径优化
// 优化关键渲染路径
class CriticalRenderPath {
constructor() {
this.criticalCSS = '';
this.criticalJS = '';
}
extractCriticalCSS() {
// 提取首屏关键CSS
const styles = document.querySelectorAll('style, link[rel="stylesheet"]');
let criticalCSS = '';
styles.forEach(style => {
if (this.isAboveTheFold(style)) {
criticalCSS += style.textContent || '';
}
});
return criticalCSS;
}
inlineCriticalResources() {
// 内联关键CSS
const style = document.createElement('style');
style.textContent = this.criticalCSS;
document.head.appendChild(style);
// 异步加载非关键CSS
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = '/non-critical.css';
link.media = 'print';
link.onload = () => {
link.media = 'all';
};
document.head.appendChild(link);
}
}
3.2 图片优化
// 图片懒加载与优化
class ImageOptimizer {
constructor() {
this.observer = new IntersectionObserver(this.handleIntersection.bind(this), {
rootMargin: '50px',
threshold: 0.1
});
}
lazyLoadImages() {
const images = document.querySelectorAll('img[data-src]');
images.forEach(img => this.observer.observe(img));
}
handleIntersection(entries) {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
this.loadImage(img);
this.observer.unobserve(img);
}
});
}
loadImage(img) {
const src = img.getAttribute('data-src');
if (!src) return;
// 使用WebP格式(如果支持)
const webpSrc = src.replace(/\.(jpg|jpeg|png)$/, '.webp');
const image = new Image();
image.onload = () => {
img.src = image.src;
img.classList.add('loaded');
};
// 检查WebP支持
if (this.supportsWebP()) {
image.src = webpSrc;
} else {
image.src = src;
}
}
supportsWebP() {
const canvas = document.createElement('canvas');
if (canvas.getContext && canvas.getContext('2d')) {
return canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0;
}
return false;
}
}
四、JavaScript优化
4.1 代码分割与懒加载
// 动态导入与代码分割
const loadModule = async (moduleName) => {
try {
// 动态导入
const module = await import(`./modules/${moduleName}.js`);
return module;
} catch (error) {
console.error(`加载模块失败: ${moduleName}`, error);
return null;
}
};
// 基于路由的代码分割
const routes = {
'/home': () => import('./pages/Home.js'),
'/about': () => import('./pages/About.js'),
'/contact': () => import('./pages/Contact.js')
};
// 预加载路由
const preloadRoutes = () => {
Object.values(routes).forEach(loader => {
loader().then(module => {
console.log('预加载完成:', module);
});
});
};
// 按需加载
const loadRoute = async (path) => {
const loader = routes[path];
if (loader) {
const module = await loader();
return module.default;
}
return null;
};
4.2 内存管理与性能
// 内存管理优化
class MemoryManager {
constructor() {
this.cache = new Map();
this.maxCacheSize = 100;
this.cleanupInterval = 60000; // 60秒清理一次
}
getWithCache(key, fetcher) {
// 检查缓存
const cached = this.cache.get(key);
if (cached && Date.now() - cached.timestamp < 300000) { // 5分钟缓存
return Promise.resolve(cached.data);
}
// 获取新数据
return fetcher().then(data => {
// 更新缓存
this.cache.set(key, {
data,
timestamp: Date.now()
});
// 清理旧缓存
this.cleanup();
return data;
});
}
cleanup() {
if (this.cache.size > this.maxCacheSize) {
const entries = Array.from(this.cache.entries());
entries.sort((a, b) => a[1].timestamp - b[1].timestamp);
// 删除最旧的20%条目
const toDelete = Math.floor(entries.length * 0.2);
for (let i = 0; i < toDelete; i++) {
this.cache.delete(entries[i][0]);
}
}
}
// 避免内存泄漏
removeEventListeners() {
// 清理事件监听器
document.removeEventListener('scroll', this.handleScroll);
window.removeEventListener('resize', this.handleResize);
}
// 使用WeakMap避免内存泄漏
createWeakCache() {
const cache = new WeakMap();
return {
get: (key) => cache.get(key),
set: (key, value) => cache.set(key, value)
};
}
}
五、CSS优化
5.1 减少重绘与重排
/* 优化CSS选择器性能 */
/* 避免使用通配符 */
* { margin: 0; padding: 0; } /* 不推荐 */
/* 使用类选择器 */
.button { /* 推荐 */ }
/* 避免深层嵌套 */
.container .wrapper .content .item { /* 不推荐 */ }
.item { /* 推荐 */ }
/* 使用transform和opacity触发GPU加速 */
.animate {
transform: translateZ(0);
will-change: transform;
}
/* 避免布局抖动 */
.stable-element {
position: fixed;
width: 100%;
height: 60px;
}
/* 使用contain属性优化渲染 */
.isolated {
contain: layout style paint;
}
.widget {
contain: content;
}
5.2 关键CSS提取
// 提取关键CSS
const critical = require('critical');
critical.generate({
base: 'dist/',
src: 'index.html',
dest: 'dist/index-critical.html',
inline: true,
extract: true,
dimensions: [
{ width: 320, height: 480 }, // 手机
{ width: 768, height: 1024 }, // 平板
{ width: 1200, height: 800 } // 桌面
],
penthouse: {
timeout: 30000,
maxEmbeddedBase64Length: 1000
}
});
六、构建优化
6.1 Webpack优化配置
// webpack.config.js
const path = require('path');
const TerserPlugin = require('terser-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
filename: '[name].[contenthash:8].js',
path: path.resolve(__dirname, 'dist'),
clean: true
},
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
parallel: true,
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true
},
output: {
comments: false
}
}
}),
new CssMinimizerPlugin()
],
// 代码分割
splitChunks: {
chunks: 'all',
minSize: 20000,
minChunks: 1,
maxAsyncRequests: 30,
maxInitialRequests: 30,
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
},
commons: {
name: 'commons',
minChunks: 2,
chunks: 'initial',
minSize: 0
}
}
},
// 运行时优化
runtimeChunk: 'single'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: ['@babel/plugin-syntax-dynamic-import']
}
}
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
require('autoprefixer'),
require('cssnano')
]
}
}
}
]
}
]
},
plugins: [
new BundleAnalyzerPlugin({
analyzerMode: 'static',
reportFilename: 'bundle-report.html',
openAnalyzer: false
})
],
// 性能提示
performance: {
hints: 'warning',
maxEntrypointSize: 512000,
maxAssetSize: 512000
}
};
6.2 Tree Shaking与代码压缩
// package.json配置
{
"name": "my-app",
"sideEffects": [
"*.css",
"*.scss",
"*.less"
],
"exports": {
".": {
"import": "./dist/esm/index.js",
"require": "./dist/cjs/index.js"
},
"./styles.css": "./dist/styles.css"
}
}
// rollup.config.js
import { terser } from 'rollup-plugin-terser';
import { visualizer } from 'rollup-plugin-visualizer';
export default {
input: 'src/index.js',
output: [
{
file: 'dist/bundle.esm.js',
format: 'esm',
sourcemap: true
},
{
file: 'dist/bundle.cjs.js',
format: 'cjs',
sourcemap: true
}
],
plugins: [
terser({
compress: {
pure_funcs: ['console.log', 'console.debug']
}
}),
visualizer({
filename: 'bundle-analysis.html',
open: true
})
]
};
七、缓存策略
7.1 HTTP缓存
# Nginx缓存配置
server {
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
add_header Vary Accept-Encoding;
# 启用Brotli压缩
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css application/javascript application/json image/svg+xml;
}
location ~* \.(html)$ {
expires 1h;
add_header Cache-Control "public, must-revalidate";
}
# API缓存
location /api/ {
proxy_cache api_cache;
proxy_cache_valid 200 302 5m;
proxy_cache_valid 404 1m;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
add_header X-Cache-Status $upstream_cache_status;
}
}
7.2 Service Worker缓存
// service-worker.js
const CACHE_NAME = 'my-app-v1';
const urlsToCache = [
'/',
'/index.html',
'/styles/main.css',
'/scripts/main.js',
'/images/logo.png'
];
// 安装Service Worker
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => cache.addAll(urlsToCache))
);
});
// 激活Service Worker
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (cacheName !== CACHE_NAME) {
return caches.delete(cacheName);
}
})
);
})
);
});
// 拦截请求
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => {
// 缓存命中
if (response) {
return response;
}
// 网络请求
return fetch(event.request)
.then(response => {
// 检查响应是否有效
if (!response || response.status !== 200 || response.type !== 'basic') {
return response;
}
// 克隆响应
const responseToCache = response.clone();
// 缓存新资源
caches.open(CACHE_NAME)
.then(cache => {
cache.put(event.request, responseToCache);
});
return response;
});
})
);
});
八、性能测试与监控
8.1 自动化性能测试
// 使用Lighthouse进行性能测试
const lighthouse = require('lighthouse');
const chromeLauncher = require('chrome-launcher');
async function runLighthouse(url) {
const chrome = await chromeLauncher.launch({
chromeFlags: ['--headless']
});
const options = {
logLevel: 'info',
output: 'html',
onlyCategories: ['performance'],
port: chrome.port
};
const runnerResult = await lighthouse(url, options);
await chrome.kill();
return {
score: runnerResult.lhr.categories.performance.score * 100,
metrics: runnerResult.lhr.audits
};
}
// 性能预算监控
const performanceBudget = {
'first-contentful-paint': 1000,
'largest-contentful-paint': 2500,
'first-input-delay': 100,
'cumulative-layout-shift': 0.1,
'total-blocking-time': 300,
'speed-index': 1000
};
function checkPerformanceBudget(metrics) {
const violations = [];
Object.entries(performanceBudget).forEach(([metric, budget]) => {
const value = metrics[metric]?.numericValue;
if (value && value > budget) {
violations.push({
metric,
value,
budget,
difference: value - budget
});
}
});
return violations;
}
九、总结与最佳实践
9.1 性能优化检查清单
-
✅ 网络优化
- 启用HTTP/2或HTTP/3
- 使用CDN分发资源
- 启用Gzip/Brotli压缩
- 配置合适的缓存策略
-
✅ 资源优化
- 图片优化(WebP、懒加载)
- 字体优化(子集化、预加载)
- 代码分割与懒加载
- 移除未使用的代码
-
✅ 渲染优化
- 优化关键渲染路径
- 减少重绘与重排
- 使用CSS Containment
- 避免布局抖动
-
✅ JavaScript优化
- 避免长时间任务
- 使用Web Workers
- 优化事件处理
- 内存管理
-
✅ 构建优化
- Tree Shaking
- 代码压缩
- 源映射优化
- 模块联邦
9.2 持续性能优化
# 性能监控配置
performance:
monitoring:
enabled: true
interval: 5m
metrics:
- "first-contentful-paint"
- "largest-contentful-paint"
- "first-input-delay"
- "cumulative-layout-shift"
alerts:
thresholds:
fcp: 1000
lcp: 2500
fid: 100
cls: 0.1
optimization:
auto: true
schedule: "0 2 * * *" # 每天凌晨2点
9.3 性能文化
- 性能优先:在项目初期就考虑性能
- 持续监控:建立完善的性能监控体系
- 团队协作:性能优化需要全团队参与
- 数据驱动:基于数据做优化决策
- 持续改进:性能优化是持续的过程
通过实施这些性能优化策略,你可以显著提升Web应用的性能,提供更好的用户体验,同时也能在搜索引擎排名中获得优势。