性能监控
性能监控概述
前端性能监控是优化用户体验的重要手段,主要包括:
- 性能指标:Web Vitals、自定义指标
- 性能采集:Performance API
- 性能分析:统计、可视化、优化建议
Web Vitals
Core Web Vitals
1. LCP (Largest Contentful Paint)
- 定义:最大内容绘制时间
- 目标:< 2.5s
- 测量:最大可见元素的渲染时间
2. FID (First Input Delay)
- 定义:首次输入延迟
- 目标:< 100ms
- 测量:用户首次交互到浏览器响应的时间
3. CLS (Cumulative Layout Shift)
- 定义:累积布局偏移
- 目标:< 0.1
- 测量:页面布局不稳定的程度
测量 Web Vitals
LCP:
new PerformanceObserver((list) => {
const entries = list.getEntries();
const lastEntry = entries[entries.length - 1];
const lcp = lastEntry.renderTime || lastEntry.loadTime;
console.log('LCP:', lcp);
// 上报
reportMetric('LCP', lcp);
}).observe({ entryTypes: ['largest-contentful-paint'] });
FID:
new PerformanceObserver((list) => {
list.getEntries().forEach(entry => {
const fid = entry.processingStart - entry.startTime;
console.log('FID:', fid);
// 上报
reportMetric('FID', fid);
});
}).observe({ entryTypes: ['first-input'] });
CLS:
let clsValue = 0;
let clsEntries = [];
new PerformanceObserver((list) => {
list.getEntries().forEach(entry => {
if (!entry.hadRecentInput) {
clsValue += entry.value;
clsEntries.push(entry);
}
});
// 上报
reportMetric('CLS', clsValue);
}).observe({ entryTypes: ['layout-shift'] });
Performance API
Navigation Timing
时间点:
const timing = performance.timing;
const metrics = {
// DNS 查询时间
dns: timing.domainLookupEnd - timing.domainLookupStart,
// TCP 连接时间
tcp: timing.connectEnd - timing.connectStart,
// 请求响应时间
request: timing.responseEnd - timing.requestStart,
// DOM 解析时间
domParse: timing.domInteractive - timing.responseEnd,
// 资源加载时间
resourceLoad: timing.loadEventEnd - timing.domContentLoadedEventEnd,
// 页面加载时间
pageLoad: timing.loadEventEnd - timing.navigationStart,
// 首字节时间
ttfb: timing.responseStart - timing.requestStart,
};
Resource Timing
资源加载时间:
performance.getEntriesByType('resource').forEach(resource => {
const metrics = {
name: resource.name,
duration: resource.duration,
size: resource.transferSize,
type: resource.initiatorType,
// DNS 时间
dns: resource.domainLookupEnd - resource.domainLookupStart,
// TCP 时间
tcp: resource.connectEnd - resource.connectStart,
// 请求时间
request: resource.responseStart - resource.requestStart,
// 响应时间
response: resource.responseEnd - resource.responseStart,
};
// 上报慢资源
if (metrics.duration > 1000) {
reportSlowResource(metrics);
}
});
Performance Observer
监听性能指标:
// 监听所有性能条目
const observer = new PerformanceObserver((list) => {
list.getEntries().forEach(entry => {
console.log(entry.name, entry.duration);
});
});
observer.observe({
entryTypes: ['navigation', 'resource', 'paint', 'measure']
});
自定义指标
页面加载时间
window.addEventListener('load', () => {
const loadTime = performance.timing.loadEventEnd - performance.timing.navigationStart;
reportMetric('pageLoad', loadTime);
});
首屏时间
function getFirstScreenTime() {
return new Promise((resolve) => {
const observer = new PerformanceObserver((list) => {
const entries = list.getEntries();
const firstScreenEntry = entries.find(entry =>
entry.name.includes('first-screen')
);
if (firstScreenEntry) {
resolve(firstScreenEntry.duration);
observer.disconnect();
}
});
observer.observe({ entryTypes: ['measure'] });
// 标记首屏
performance.mark('first-screen-start');
// 首屏渲染完成后
setTimeout(() => {
performance.mark('first-screen-end');
performance.measure('first-screen', 'first-screen-start', 'first-screen-end');
}, 0);
});
}
接口响应时间
// 封装 fetch
const originalFetch = window.fetch;
window.fetch = function(...args) {
const startTime = performance.now();
return originalFetch.apply(this, args)
.then(response => {
const duration = performance.now() - startTime;
reportMetric('api', {
url: args[0],
duration,
status: response.status,
});
return response;
});
};
性能上报
基础上报
function reportMetric(name, value, tags = {}) {
const data = {
name,
value,
tags: {
...tags,
url: window.location.href,
userAgent: navigator.userAgent,
timestamp: Date.now(),
},
};
// 使用 sendBeacon
if (navigator.sendBeacon) {
navigator.sendBeacon('/api/metrics', JSON.stringify(data));
} else {
// 降级方案
const img = new Image();
img.src = `/api/metrics?data=${encodeURIComponent(JSON.stringify(data))}`;
}
}
批量上报
class PerformanceCollector {
constructor() {
this.metrics = [];
this.timer = null;
}
collect(name, value, tags) {
this.metrics.push({ name, value, tags, timestamp: Date.now() });
if (this.metrics.length >= 20) {
this.report();
} else {
this.scheduleReport();
}
}
scheduleReport() {
if (this.timer) {
clearTimeout(this.timer);
}
this.timer = setTimeout(() => {
this.report();
}, 10000); // 10秒后上报
}
report() {
if (this.metrics.length === 0) return;
const data = this.metrics.slice();
this.metrics = [];
fetch('/api/metrics', {
method: 'POST',
body: JSON.stringify(data),
}).catch(err => {
console.error('Report failed:', err);
this.metrics.unshift(...data);
});
}
}
性能分析
1. 性能统计
统计维度:
- 平均值
- 中位数
- P75、P95、P99
- 最大值、最小值
2. 性能趋势
趋势分析:
- 时间趋势
- 版本对比
- 用户分布
3. 性能优化建议
自动分析:
- 慢资源识别
- 性能瓶颈定位
- 优化建议生成
监控平台
1. Google Analytics
集成:
// 发送自定义指标
gtag('event', 'timing_complete', {
name: 'load',
value: loadTime,
});
2. 自建监控
服务端接口:
app.post('/api/metrics', (req, res) => {
const metrics = req.body;
// 存储指标
saveMetrics(metrics);
// 分析性能
analyzePerformance(metrics);
res.json({ success: true });
});
最佳实践
1. 指标采集
- 采集核心指标(Web Vitals)
- 采集自定义指标
- 采集资源加载时间
- 采集接口响应时间
2. 上报策略
- 批量上报
- 采样上报(减少数据量)
- 失败重试
- 页面卸载时上报
3. 性能分析
- 统计性能指标
- 分析性能趋势
- 定位性能瓶颈
- 生成优化建议
4. 告警机制
- 性能阈值告警
- 异常波动告警
- 自动通知