返回博客列表
性能优化
Web 性能监控与优化
2025-08-28
14 分钟阅读
性能优化监控Web

Web 性能监控与优化
Web 性能直接影响用户体验和业务指标。建立完善的性能监控体系,持续优化应用性能,是现代 Web 开发的重要任务。
性能指标
1. 核心 Web 指标 (Core Web Vitals)
// 测量 LCP (Largest Contentful Paint)
const observer = new PerformanceObserver((list) => {
const entries = list.getEntries()
const lastEntry = entries[entries.length - 1]
console.log('LCP:', lastEntry.startTime)
})
observer.observe({ entryTypes: ['largest-contentful-paint'] })
// 测量 FID (First Input Delay)
const fidObserver = new PerformanceObserver((list) => {
const entries = list.getEntries()
entries.forEach(entry => {
console.log('FID:', entry.processingStart - entry.startTime)
})
})
fidObserver.observe({ entryTypes: ['first-input'] })
// 测量 CLS (Cumulative Layout Shift)
let clsValue = 0
const clsObserver = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (!entry.hadRecentInput) {
clsValue += entry.value
}
}
console.log('CLS:', clsValue)
})
clsObserver.observe({ entryTypes: ['layout-shift'] })
2. 自定义性能指标
// 页面加载时间
const pageLoadTime = performance.timing.loadEventEnd - performance.timing.navigationStart
console.log('页面加载时间:', pageLoadTime)
// 首屏渲染时间
const firstPaint = performance.getEntriesByType('paint')[0]
console.log('首屏渲染时间:', firstPaint.startTime)
// 资源加载时间
const resources = performance.getEntriesByType('resource')
resources.forEach(resource => {
console.log(`${resource.name}: ${resource.duration}ms`)
})
性能监控工具
1. 自定义监控
class PerformanceMonitor {
constructor() {
this.metrics = {}
this.init()
}
init() {
// 监听页面加载完成
window.addEventListener('load', () => {
this.collectMetrics()
})
// 监听页面卸载
window.addEventListener('beforeunload', () => {
this.sendMetrics()
})
}
collectMetrics() {
// 收集性能指标
this.metrics = {
// 页面加载时间
pageLoadTime: performance.timing.loadEventEnd - performance.timing.navigationStart,
// DNS 查询时间
dnsTime: performance.timing.domainLookupEnd - performance.timing.domainLookupStart,
// TCP 连接时间
tcpTime: performance.timing.connectEnd - performance.timing.connectStart,
// 请求响应时间
requestTime: performance.timing.responseEnd - performance.timing.requestStart,
// DOM 解析时间
domParseTime: performance.timing.domContentLoadedEventEnd - performance.timing.domLoading,
// 首屏渲染时间
firstPaint: this.getFirstPaint(),
// 最大内容绘制时间
lcp: this.getLCP(),
// 首次输入延迟
fid: this.getFID(),
// 累积布局偏移
cls: this.getCLS()
}
}
getFirstPaint() {
const paintEntries = performance.getEntriesByType('paint')
const firstPaint = paintEntries.find(entry => entry.name === 'first-paint')
return firstPaint ? firstPaint.startTime : 0
}
getLCP() {
return new Promise((resolve) => {
const observer = new PerformanceObserver((list) => {
const entries = list.getEntries()
const lastEntry = entries[entries.length - 1]
resolve(lastEntry.startTime)
})
observer.observe({ entryTypes: ['largest-contentful-paint'] })
})
}
getFID() {
return new Promise((resolve) => {
const observer = new PerformanceObserver((list) => {
const entries = list.getEntries()
entries.forEach(entry => {
resolve(entry.processingStart - entry.startTime)
})
})
observer.observe({ entryTypes: ['first-input'] })
})
}
getCLS() {
let clsValue = 0
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (!entry.hadRecentInput) {
clsValue += entry.value
}
}
})
observer.observe({ entryTypes: ['layout-shift'] })
return clsValue
}
sendMetrics() {
// 发送指标到监控系统
fetch('/api/metrics', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
...this.metrics,
url: window.location.href,
timestamp: Date.now(),
userAgent: navigator.userAgent
})
})
}
}
// 初始化监控
const monitor = new PerformanceMonitor()
2. 第三方监控工具
// 使用 Google Analytics
gtag('config', 'GA_MEASUREMENT_ID', {
custom_map: {
'custom_parameter_1': 'page_load_time',
'custom_parameter_2': 'first_paint'
}
})
// 发送自定义指标
gtag('event', 'page_performance', {
page_load_time: pageLoadTime,
first_paint: firstPaint,
lcp: lcpValue
})
// 使用 Sentry 监控错误
Sentry.init({
dsn: 'YOUR_DSN',
integrations: [
new Sentry.BrowserTracing({
tracingOrigins: ['localhost', 'your-domain.com']
})
],
tracesSampleRate: 1.0
})
性能优化策略
1. 资源优化
// 图片懒加载
class LazyImageLoader {
constructor() {
this.observer = new IntersectionObserver(this.handleIntersection.bind(this))
this.images = document.querySelectorAll('img[data-src]')
this.images.forEach(img => this.observer.observe(img))
}
handleIntersection(entries) {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target
img.src = img.dataset.src
img.classList.remove('lazy')
this.observer.unobserve(img)
}
})
}
}
// 代码分割
const LazyComponent = React.lazy(() => import('./LazyComponent'))
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
)
}
// 预加载关键资源
const preloadResource = (href, as) => {
const link = document.createElement('link')
link.rel = 'preload'
link.href = href
link.as = as
document.head.appendChild(link)
}
// 预加载关键 CSS
preloadResource('/styles/critical.css', 'style')
2. 缓存策略
// Service Worker 缓存
const CACHE_NAME = 'app-cache-v1'
const urlsToCache = [
'/',
'/styles/main.css',
'/scripts/main.js',
'/images/logo.png'
]
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => cache.addAll(urlsToCache))
)
})
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => {
if (response) {
return response
}
return fetch(event.request)
})
)
})
// HTTP 缓存头
app.use(express.static('public', {
maxAge: '1y',
etag: true,
lastModified: true
}))
3. 网络优化
// 请求去重
class RequestDeduplicator {
constructor() {
this.pendingRequests = new Map()
}
async request(url, options = {}) {
const key = `${url}-${JSON.stringify(options)}`
if (this.pendingRequests.has(key)) {
return this.pendingRequests.get(key)
}
const promise = fetch(url, options)
this.pendingRequests.set(key, promise)
try {
const result = await promise
this.pendingRequests.delete(key)
return result
} catch (error) {
this.pendingRequests.delete(key)
throw error
}
}
}
// 请求重试
const retryRequest = async (url, options = {}, maxRetries = 3) => {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch(url, options)
if (response.ok) {
return response
}
} catch (error) {
if (i === maxRetries - 1) {
throw error
}
await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, i)))
}
}
}
性能分析工具
1. Chrome DevTools
// 性能分析
const startProfiling = () => {
if (performance.mark) {
performance.mark('start-profiling')
}
}
const endProfiling = () => {
if (performance.mark) {
performance.mark('end-profiling')
performance.measure('profiling-duration', 'start-profiling', 'end-profiling')
}
}
// 内存使用分析
const analyzeMemory = () => {
if (performance.memory) {
console.log('内存使用情况:', {
used: performance.memory.usedJSHeapSize,
total: performance.memory.totalJSHeapSize,
limit: performance.memory.jsHeapSizeLimit
})
}
}
2. 自动化性能测试
// 使用 Puppeteer 进行性能测试
const puppeteer = require('puppeteer')
async function performanceTest() {
const browser = await puppeteer.launch()
const page = await browser.newPage()
// 启用性能监控
await page.tracing.start({ path: 'trace.json' })
// 访问页面
await page.goto('https://example.com')
// 等待页面加载完成
await page.waitForLoadState('networkidle')
// 获取性能指标
const metrics = await page.evaluate(() => {
const navigation = performance.getEntriesByType('navigation')[0]
return {
loadTime: navigation.loadEventEnd - navigation.loadEventStart,
domContentLoaded: navigation.domContentLoadedEventEnd - navigation.domContentLoadedEventStart,
firstPaint: performance.getEntriesByType('paint')[0].startTime
}
})
console.log('性能指标:', metrics)
// 停止性能监控
await page.tracing.stop()
await browser.close()
}
持续优化
1. 性能预算
// 性能预算配置
const performanceBudget = {
pageLoadTime: 3000, // 3秒
firstPaint: 1500, // 1.5秒
lcp: 2500, // 2.5秒
fid: 100, // 100ms
cls: 0.1 // 0.1
}
// 检查性能预算
const checkPerformanceBudget = (metrics) => {
const violations = []
Object.keys(performanceBudget).forEach(key => {
if (metrics[key] > performanceBudget[key]) {
violations.push({
metric: key,
actual: metrics[key],
budget: performanceBudget[key]
})
}
})
if (violations.length > 0) {
console.warn('性能预算超标:', violations)
// 发送告警
sendAlert(violations)
}
}
2. 自动化优化
// 自动优化图片
const optimizeImages = () => {
const images = document.querySelectorAll('img')
images.forEach(img => {
if (img.dataset.src && !img.src) {
// 使用 WebP 格式
const webpSrc = img.dataset.src.replace(/.(jpg|jpeg|png)$/, '.webp')
img.src = webpSrc
}
})
}
// 自动预加载关键资源
const preloadCriticalResources = () => {
const criticalResources = [
'/styles/critical.css',
'/scripts/critical.js',
'/fonts/main.woff2'
]
criticalResources.forEach(resource => {
const link = document.createElement('link')
link.rel = 'preload'
link.href = resource
link.as = resource.endsWith('.css') ? 'style' : 'script'
document.head.appendChild(link)
})
}
总结
Web 性能监控与优化是一个持续的过程,需要:
- 建立完善的监控体系:收集关键性能指标
- 使用合适的工具:选择合适的监控和分析工具
- 实施优化策略:从资源、缓存、网络等方面优化
- 持续改进:建立性能预算,持续监控和优化
通过系统性的性能优化,我们可以显著提升用户体验,改善业务指标。记住,性能优化不是一次性的工作,而是需要持续关注和改进的过程。