Appearance
性能监控
性能监控是确保 Web 应用持续高性能的关键实践。本指南将详细介绍如何实现全面的性能监控,包括前端性能指标、后端性能指标和用户行为监控。
Web 性能指标
Core Web Vitals
javascript
// Core Web Vitals 监控
class CoreWebVitalsMonitor {
constructor() {
this.metrics = {
CLS: 0, // Cumulative Layout Shift
FID: 0, // First Input Delay
LCP: 0 // Largest Contentful Paint
};
this.observerCallbacks = [];
}
// 监控累积布局偏移 (CLS)
measureCLS() {
let clsValue = 0;
let clsEntries = [];
const clsObserver = new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
// 只计算非动画引起的布局偏移
if (!entry.hadRecentInput) {
clsValue += entry.value;
clsEntries.push(entry);
}
}
// 报告 CLS 值
this.reportMetric('CLS', clsValue, clsEntries);
});
clsObserver.observe({ entryTypes: ['layout-shift'] });
}
// 监控首次输入延迟 (FID)
measureFID() {
const fidObserver = new PerformanceObserver((entryList) => {
const firstInput = entryList.getEntries()[0];
const fidValue = firstInput.processingStart - firstInput.startTime;
this.reportMetric('FID', fidValue, firstInput);
});
fidObserver.observe({ entryTypes: ['first-input'] });
}
// 监控最大内容绘制 (LCP)
measureLCP() {
let lcpValue = 0;
let lcpEntry = null;
const lcpObserver = new PerformanceObserver((entryList) => {
const entries = entryList.getEntries();
const lastEntry = entries[entries.length - 1];
lcpValue = lastEntry.startTime;
lcpEntry = lastEntry;
// 如果页面隐藏,报告最终的 LCP 值
if (document.visibilityState === 'hidden') {
this.reportMetric('LCP', lcpValue, lcpEntry);
}
});
lcpObserver.observe({ entryTypes: ['largest-contentful-paint'] });
// 页面隐藏时报告 LCP
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden' && lcpEntry) {
this.reportMetric('LCP', lcpValue, lcpEntry);
}
});
}
// 监控首次内容绘制 (FCP)
measureFCP() {
const fcpObserver = new PerformanceObserver((entryList) => {
const fcpEntry = entryList.getEntries()[0];
this.reportMetric('FCP', fcpEntry.startTime, fcpEntry);
});
fcpObserver.observe({ entryTypes: ['paint'] });
}
// 监控首次绘制 (FP)
measureFP() {
const fpObserver = new PerformanceObserver((entryList) => {
const fpEntry = entryList.getEntries()[0];
this.reportMetric('FP', fpEntry.startTime, fpEntry);
});
fpObserver.observe({ entryTypes: ['paint'] });
}
// 报告性能指标
reportMetric(name, value, entry) {
const metric = {
name,
value,
entry,
timestamp: Date.now(),
url: window.location.href
};
// 调用观察者回调
this.observerCallbacks.forEach(callback => callback(metric));
// 发送到分析服务
this.sendToAnalytics(metric);
}
// 添加观察者
addObserver(callback) {
this.observerCallbacks.push(callback);
}
// 发送到分析服务
sendToAnalytics(metric) {
// 发送到后端分析服务
if (navigator.sendBeacon) {
navigator.sendBeacon('/api/performance', JSON.stringify(metric));
} else {
// 降级方案
fetch('/api/performance', {
method: 'POST',
body: JSON.stringify(metric),
keepalive: true
});
}
}
// 初始化所有监控
init() {
this.measureCLS();
this.measureFID();
this.measureLCP();
this.measureFCP();
this.measureFP();
}
}
// 使用 Core Web Vitals 监控
const vitalsMonitor = new CoreWebVitalsMonitor();
// 添加自定义观察者
vitalsMonitor.addObserver((metric) => {
console.log(`${metric.name}: ${metric.value}`);
// 根据指标值触发优化
if (metric.name === 'CLS' && metric.value > 0.1) {
console.warn('Layout shift is too high:', metric.value);
}
});
vitalsMonitor.init();
自定义性能指标
javascript
// 自定义性能指标监控
class CustomPerformanceMonitor {
constructor() {
this.metrics = new Map();
this.timings = new Map();
}
// 记录自定义时间
mark(name) {
performance.mark(name);
}
// 测量自定义时间间隔
measure(name, startMark, endMark = undefined) {
if (!endMark) {
endMark = `end-${name}`;
performance.mark(endMark);
}
performance.measure(name, startMark, endMark);
const measure = performance.getEntriesByName(name)[0];
this.timings.set(name, measure.duration);
return measure.duration;
}
// 记录组件渲染时间
measureComponentRender(componentName, renderFunction) {
const startMark = `render-${componentName}-start`;
const endMark = `render-${componentName}-end`;
performance.mark(startMark);
const result = renderFunction();
performance.mark(endMark);
performance.measure(`render-${componentName}`, startMark, endMark);
const measure = performance.getEntriesByName(`render-${componentName}`)[0];
this.reportMetric('ComponentRenderTime', measure.duration, {
componentName,
duration: measure.duration
});
return result;
}
// 监控 API 调用时间
async measureApiCall(url, options = {}) {
const startMark = `api-${Date.now()}`;
performance.mark(startMark);
try {
const response = await fetch(url, options);
const endMark = `api-${Date.now()}-end`;
performance.mark(endMark);
performance.measure(`api-${url}`, startMark, endMark);
const measure = performance.getEntriesByName(`api-${url}`)[0];
this.reportMetric('ApiCallTime', measure.duration, {
url,
method: options.method || 'GET',
status: response.status,
duration: measure.duration
});
return response;
} catch (error) {
const endMark = `api-${Date.now()}-end`;
performance.mark(endMark);
performance.measure(`api-${url}`, startMark, endMark);
const measure = performance.getEntriesByName(`api-${url}`)[0];
this.reportMetric('ApiCallError', measure.duration, {
url,
method: options.method || 'GET',
error: error.message,
duration: measure.duration
});
throw error;
}
}
// 监控资源加载时间
measureResourceLoad(url) {
return new Promise((resolve, reject) => {
const resourceObserver = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.name === url) {
this.reportMetric('ResourceLoadTime', entry.duration, {
url: entry.name,
duration: entry.duration,
entryType: entry.entryType
});
resolve(entry);
resourceObserver.disconnect();
}
}
});
resourceObserver.observe({ entryTypes: ['resource'] });
// 超时处理
setTimeout(() => {
reject(new Error(`Resource load timeout: ${url}`));
resourceObserver.disconnect();
}, 30000);
});
}
// 报告指标
reportMetric(name, value, details = {}) {
const metric = {
name,
value,
details,
timestamp: Date.now(),
userAgent: navigator.userAgent,
url: window.location.href
};
// 存储指标
if (!this.metrics.has(name)) {
this.metrics.set(name, []);
}
this.metrics.get(name).push(metric);
// 发送到分析服务
this.sendToAnalytics(metric);
}
// 发送到分析服务
sendToAnalytics(metric) {
// 批量发送以减少请求数量
if (!this.batch) {
this.batch = [];
}
this.batch.push(metric);
if (this.batch.length >= 10 || Date.now() - (this.lastSend || 0) > 5000) {
this.sendBatch();
}
}
sendBatch() {
if (this.batch && this.batch.length > 0) {
if (navigator.sendBeacon) {
navigator.sendBeacon('/api/performance-batch', JSON.stringify(this.batch));
} else {
fetch('/api/performance-batch', {
method: 'POST',
body: JSON.stringify(this.batch),
keepalive: true
});
}
this.batch = [];
this.lastSend = Date.now();
}
}
// 获取指标统计
getStats() {
const stats = {};
for (const [name, metrics] of this.metrics) {
const values = metrics.map(m => m.value);
stats[name] = {
count: values.length,
average: values.reduce((a, b) => a + b, 0) / values.length,
min: Math.min(...values),
max: Math.max(...values),
p95: this.getPercentile(values, 95),
p99: this.getPercentile(values, 99)
};
}
return stats;
}
getPercentile(array, percentile) {
const sorted = array.slice().sort((a, b) => a - b);
const index = Math.ceil(percentile / 100 * sorted.length) - 1;
return sorted[Math.max(0, index)];
}
}
// 使用自定义性能监控
const customMonitor = new CustomPerformanceMonitor();
// 监控组件渲染
customMonitor.measureComponentRender('UserDashboard', () => {
// 组件渲染逻辑
return document.createElement('div');
});
// 监控 API 调用
customMonitor.measureApiCall('/api/users', { method: 'GET' });
后端性能监控
Node.js 性能监控
javascript
// Node.js 性能监控
const os = require('os');
const cluster = require('cluster');
class NodePerformanceMonitor {
constructor(options = {}) {
this.options = {
interval: options.interval || 5000, // 5秒
metricsEndpoint: options.metricsEndpoint || '/metrics',
...options
};
this.metrics = {
cpu: [],
memory: [],
eventLoop: [],
heap: []
};
this.startMonitoring();
}
// 开始监控
startMonitoring() {
this.cpuInterval = setInterval(() => {
this.collectCpuMetrics();
}, this.options.interval);
this.memoryInterval = setInterval(() => {
this.collectMemoryMetrics();
}, this.options.interval);
this.eventLoopInterval = setInterval(() => {
this.collectEventLoopMetrics();
}, this.options.interval);
}
// 收集 CPU 指标
collectCpuMetrics() {
const cpus = os.cpus();
const cpuInfo = {
count: cpus.length,
model: cpus[0].model,
speed: cpus[0].speed,
usage: this.getCpuUsage(),
timestamp: Date.now()
};
this.metrics.cpu.push(cpuInfo);
this.sendMetric('cpu', cpuInfo);
// 保持最近 100 个数据点
if (this.metrics.cpu.length > 100) {
this.metrics.cpu.shift();
}
}
// 获取 CPU 使用率
getCpuUsage() {
const cpus = os.cpus();
let user = 0, nice = 0, sys = 0, idle = 0, irq = 0;
cpus.forEach(cpu => {
user += cpu.times.user;
nice += cpu.times.nice;
sys += cpu.times.sys;
idle += cpu.times.idle;
irq += cpu.times.irq;
});
const total = user + nice + sys + idle + irq;
const usage = (total - idle) / total * 100;
return {
usage: usage,
breakdown: { user, nice, sys, idle, irq }
};
}
// 收集内存指标
collectMemoryMetrics() {
const memoryInfo = {
total: os.totalmem(),
free: os.freemem(),
used: os.totalmem() - os.freemem(),
usage: (os.totalmem() - os.freemem()) / os.totalmem() * 100,
rss: process.memoryUsage().rss,
heapTotal: process.memoryUsage().heapTotal,
heapUsed: process.memoryUsage().heapUsed,
external: process.memoryUsage().external,
arrayBuffers: process.memoryUsage().arrayBuffers,
timestamp: Date.now()
};
this.metrics.memory.push(memoryInfo);
this.sendMetric('memory', memoryInfo);
if (this.metrics.memory.length > 100) {
this.metrics.memory.shift();
}
}
// 收集事件循环指标
collectEventLoopMetrics() {
const start = process.hrtime.bigint();
setImmediate(() => {
const end = process.hrtime.bigint();
const delay = Number(end - start);
const eventLoopInfo = {
delay: delay,
timestamp: Date.now()
};
this.metrics.eventLoop.push(eventLoopInfo);
this.sendMetric('eventLoop', eventLoopInfo);
if (this.metrics.eventLoop.length > 100) {
this.metrics.eventLoop.shift();
}
});
}
// 发送指标
sendMetric(type, data) {
// 发送到监控服务
console.log(`Performance Metric - ${type}:`, data);
// 在实际应用中,这里会发送到监控服务
// 例如:Prometheus、DataDog、New Relic 等
}
// 获取指标统计
getStats() {
return {
cpu: this.getMetricStats(this.metrics.cpu),
memory: this.getMetricStats(this.metrics.memory),
eventLoop: this.getMetricStats(this.metrics.eventLoop)
};
}
getMetricStats(metricArray) {
if (metricArray.length === 0) return null;
const values = metricArray.map(m => typeof m === 'object' ? m.usage || m.delay : m);
const avg = values.reduce((a, b) => a + b, 0) / values.length;
const min = Math.min(...values);
const max = Math.max(...values);
return { avg, min, max, count: values.length };
}
// 停止监控
stop() {
clearInterval(this.cpuInterval);
clearInterval(this.memoryInterval);
clearInterval(this.eventLoopInterval);
}
}
// Express 中间件监控
const performanceMiddleware = (monitor) => {
return (req, res, next) => {
const start = process.hrtime.bigint();
res.on('finish', () => {
const duration = Number(process.hrtime.bigint() - start);
// 记录请求性能
const requestMetric = {
method: req.method,
url: req.url,
statusCode: res.statusCode,
duration: duration / 1000000, // 转换为毫秒
timestamp: Date.now()
};
monitor.sendMetric('request', requestMetric);
});
next();
};
};
// 使用示例
const app = require('express')();
const serverMonitor = new NodePerformanceMonitor();
app.use(performanceMiddleware(serverMonitor));
app.get('/api/data', (req, res) => {
// 模拟一些处理时间
setTimeout(() => {
res.json({ data: 'sample' });
}, 100);
});
用户体验监控
用户行为监控
javascript
// 用户行为监控
class UserExperienceMonitor {
constructor(options = {}) {
this.options = {
trackClicks: options.trackClicks !== false,
trackScrolls: options.trackScrolls !== false,
trackFormInteractions: options.trackFormInteractions !== false,
samplingRate: options.samplingRate || 1.0, // 100% 采样
...options
};
this.sessionId = this.generateSessionId();
this.pageStartTime = Date.now();
this.interactions = [];
this.init();
}
init() {
if (this.options.trackClicks) {
this.trackClicks();
}
if (this.options.trackScrolls) {
this.trackScrolls();
}
if (this.options.trackFormInteractions) {
this.trackFormInteractions();
}
// 页面可见性变化
document.addEventListener('visibilitychange', () => {
this.trackVisibilityChange();
});
// 页面卸载
window.addEventListener('beforeunload', () => {
this.sendPageData();
});
}
// 生成会话 ID
generateSessionId() {
return Math.random().toString(36).substr(2, 9) + Date.now().toString(36);
}
// 跟踪点击
trackClicks() {
document.addEventListener('click', (event) => {
if (Math.random() > this.options.samplingRate) return;
const clickData = {
type: 'click',
element: event.target.tagName,
target: event.target.textContent?.substring(0, 50) || event.target.className,
x: event.clientX,
y: event.clientY,
timestamp: Date.now(),
sessionId: this.sessionId,
url: window.location.href
};
this.interactions.push(clickData);
this.sendInteractionData(clickData);
});
}
// 跟踪滚动
trackScrolls() {
let scrollTimeout;
const trackScroll = () => {
const scrollData = {
type: 'scroll',
scrollTop: window.scrollY,
scrollLeft: window.scrollX,
maxScrollTop: document.body.scrollHeight - window.innerHeight,
scrollPercent: (window.scrollY / (document.body.scrollHeight - window.innerHeight)) * 100,
timestamp: Date.now(),
sessionId: this.sessionId
};
this.interactions.push(scrollData);
this.sendInteractionData(scrollData);
};
window.addEventListener('scroll', () => {
clearTimeout(scrollTimeout);
scrollTimeout = setTimeout(trackScroll, 100);
});
}
// 跟踪表单交互
trackFormInteractions() {
document.addEventListener('input', (event) => {
if (event.target.tagName === 'INPUT' || event.target.tagName === 'TEXTAREA') {
const formData = {
type: 'form_input',
fieldName: event.target.name || event.target.id,
fieldType: event.target.type,
valueLength: event.target.value.length,
timestamp: Date.now(),
sessionId: this.sessionId
};
this.interactions.push(formData);
this.sendInteractionData(formData);
}
});
document.addEventListener('focus', (event) => {
if (event.target.tagName === 'INPUT' || event.target.tagName === 'TEXTAREA') {
const focusData = {
type: 'form_focus',
fieldName: event.target.name || event.target.id,
timestamp: Date.now(),
sessionId: this.sessionId
};
this.interactions.push(focusData);
this.sendInteractionData(focusData);
}
});
}
// 跟踪页面可见性变化
trackVisibilityChange() {
const visibilityData = {
type: 'visibility_change',
visibilityState: document.visibilityState,
timestamp: Date.now(),
sessionId: this.sessionId
};
this.interactions.push(visibilityData);
this.sendInteractionData(visibilityData);
}
// 发送交互数据
sendInteractionData(data) {
// 使用 sendBeacon 确保数据发送
if (navigator.sendBeacon) {
navigator.sendBeacon('/api/user-interactions', JSON.stringify(data));
} else {
fetch('/api/user-interactions', {
method: 'POST',
body: JSON.stringify(data),
keepalive: true
});
}
}
// 发送页面数据
sendPageData() {
const pageData = {
sessionId: this.sessionId,
pageUrl: window.location.href,
pageLoadTime: Date.now() - this.pageStartTime,
interactionCount: this.interactions.length,
interactions: this.interactions,
timestamp: Date.now(),
userAgent: navigator.userAgent,
screenResolution: `${screen.width}x${screen.height}`,
viewportSize: `${window.innerWidth}x${window.innerHeight}`
};
if (navigator.sendBeacon) {
navigator.sendBeacon('/api/page-data', JSON.stringify(pageData));
} else {
fetch('/api/page-data', {
method: 'POST',
body: JSON.stringify(pageData),
keepalive: true
});
}
}
// 获取会话统计
getSessionStats() {
const clicks = this.interactions.filter(i => i.type === 'click').length;
const scrolls = this.interactions.filter(i => i.type === 'scroll').length;
const formInputs = this.interactions.filter(i => i.type === 'form_input').length;
return {
sessionId: this.sessionId,
totalInteractions: this.interactions.length,
clicks,
scrolls,
formInputs,
pageLoadTime: Date.now() - this.pageStartTime,
sessionDuration: Date.now() - this.pageStartTime
};
}
}
// 使用用户行为监控
const userMonitor = new UserExperienceMonitor({
samplingRate: 0.1 // 10% 采样率
});
性能分析工具
性能分析报告
javascript
// 性能分析报告生成器
class PerformanceReportGenerator {
constructor() {
this.reports = [];
}
// 生成性能报告
generateReport(data) {
const report = {
id: this.generateReportId(),
timestamp: Date.now(),
metrics: this.analyzeMetrics(data.metrics),
recommendations: this.generateRecommendations(data.metrics),
summary: this.generateSummary(data.metrics),
metadata: {
userAgent: data.userAgent || navigator.userAgent,
url: data.url || window.location.href,
environment: data.environment || 'production'
}
};
this.reports.push(report);
return report;
}
// 分析指标
analyzeMetrics(metrics) {
const analysis = {};
// 分析加载时间
if (metrics.loadTimes) {
const loadTimes = metrics.loadTimes.map(m => m.value);
analysis.loadTime = {
average: loadTimes.reduce((a, b) => a + b, 0) / loadTimes.length,
p95: this.getPercentile(loadTimes, 95),
p99: this.getPercentile(loadTimes, 99),
issues: this.identifyLoadTimeIssues(loadTimes)
};
}
// 分析 CLS
if (metrics.CLS) {
const clsValues = metrics.CLS.map(m => m.value);
analysis.cls = {
average: clsValues.reduce((a, b) => a + b, 0) / clsValues.length,
good: clsValues.filter(v => v < 0.1).length / clsValues.length * 100,
needsImprovement: clsValues.filter(v => v >= 0.1 && v <= 0.25).length / clsValues.length * 100,
poor: clsValues.filter(v => v > 0.25).length / clsValues.length * 100
};
}
// 分析 FID
if (metrics.FID) {
const fidValues = metrics.FID.map(m => m.value);
analysis.fid = {
average: fidValues.reduce((a, b) => a + b, 0) / fidValues.length,
good: fidValues.filter(v => v < 100).length / fidValues.length * 100,
needsImprovement: fidValues.filter(v => v >= 100 && v <= 300).length / fidValues.length * 100,
poor: fidValues.filter(v => v > 300).length / fidValues.length * 100
};
}
// 分析 LCP
if (metrics.LCP) {
const lcpValues = metrics.LCP.map(m => m.value);
analysis.lcp = {
average: lcpValues.reduce((a, b) => a + b, 0) / lcpValues.length,
good: lcpValues.filter(v => v < 2500).length / lcpValues.length * 100,
needsImprovement: lcpValues.filter(v => v >= 2500 && v <= 4000).length / lcpValues.length * 100,
poor: lcpValues.filter(v => v > 4000).length / lcpValues.length * 100
};
}
return analysis;
}
// 识别加载时间问题
identifyLoadTimeIssues(loadTimes) {
const issues = [];
if (this.getPercentile(loadTimes, 95) > 3000) {
issues.push('95th percentile load time exceeds 3 seconds');
}
if (this.getPercentile(loadTimes, 50) > 2000) {
issues.push('Median load time exceeds 2 seconds');
}
return issues;
}
// 生成建议
generateRecommendations(metrics) {
const recommendations = [];
// CLS 建议
if (metrics.CLS) {
const clsValues = metrics.CLS.map(m => m.value);
const avgCls = clsValues.reduce((a, b) => a + b, 0) / clsValues.length;
if (avgCls > 0.25) {
recommendations.push({
priority: 'high',
category: 'layout',
description: 'Cumulative Layout Shift is too high',
solution: 'Reserve space for images and ads, avoid inserting content without warning'
});
}
}
// FID 建议
if (metrics.FID) {
const fidValues = metrics.FID.map(m => m.value);
const avgFid = fidValues.reduce((a, b) => a + b, 0) / fidValues.length;
if (avgFid > 300) {
recommendations.push({
priority: 'high',
category: 'interactivity',
description: 'First Input Delay is too high',
solution: 'Reduce JavaScript execution time, break up long tasks, use web workers'
});
}
}
// LCP 建议
if (metrics.LCP) {
const lcpValues = metrics.LCP.map(m => m.value);
const avgLcp = lcpValues.reduce((a, b) => a + b, 0) / lcpValues.length;
if (avgLcp > 4000) {
recommendations.push({
priority: 'high',
category: 'loading',
description: 'Largest Contentful Paint is too slow',
solution: 'Optimize largest page elements, use resource hints, improve server response time'
});
}
}
return recommendations;
}
// 生成摘要
generateSummary(metrics) {
const summary = {
overallScore: 0,
categories: {}
};
// 计算各类别分数
if (metrics.CLS) {
const clsValues = metrics.CLS.map(m => m.value);
const avgCls = clsValues.reduce((a, b) => a + b, 0) / clsValues.length;
summary.categories.cls = avgCls < 0.1 ? 'good' : avgCls < 0.25 ? 'needs-improvement' : 'poor';
}
if (metrics.FID) {
const fidValues = metrics.FID.map(m => m.value);
const avgFid = fidValues.reduce((a, b) => a + b, 0) / fidValues.length;
summary.categories.fid = avgFid < 100 ? 'good' : avgFid < 300 ? 'needs-improvement' : 'poor';
}
if (metrics.LCP) {
const lcpValues = metrics.LCP.map(m => m.value);
const avgLcp = lcpValues.reduce((a, b) => a + b, 0) / lcpValues.length;
summary.categories.lcp = avgLcp < 2500 ? 'good' : avgLcp < 4000 ? 'needs-improvement' : 'poor';
}
// 计算整体分数
const categories = Object.values(summary.categories);
const goodCount = categories.filter(c => c === 'good').length;
summary.overallScore = Math.round((goodCount / categories.length) * 100);
return summary;
}
getPercentile(array, percentile) {
const sorted = array.slice().sort((a, b) => a - b);
const index = Math.ceil(percentile / 100 * sorted.length) - 1;
return sorted[Math.max(0, index)];
}
generateReportId() {
return `report_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
// 获取历史报告
getReports() {
return this.reports;
}
}
// 使用性能报告生成器
const reportGenerator = new PerformanceReportGenerator();
// 示例:生成报告
const sampleData = {
metrics: {
CLS: [{ value: 0.15 }, { value: 0.22 }, { value: 0.08 }],
FID: [{ value: 150 }, { value: 220 }, { value: 80 }],
LCP: [{ value: 2800 }, { value: 3200 }, { value: 2100 }]
}
};
const report = reportGenerator.generateReport(sampleData);
console.log('Performance Report:', report);
性能监控最佳实践
监控策略建议
javascript
// 性能监控配置
const PerformanceConfig = {
// 采样配置
sampling: {
rate: 0.1, // 10% 采样率
minPageViews: 1000, // 最小页面访问量才开始监控
sessionTimeout: 30 * 60 * 1000 // 30分钟会话超时
},
// 阈值配置
thresholds: {
cls: { good: 0.1, poor: 0.25 },
fid: { good: 100, poor: 300 },
lcp: { good: 2500, poor: 4000 },
fcp: { good: 1800, poor: 3000 }
},
// 监控指标
metrics: [
'CLS', 'FID', 'LCP', 'FCP', 'TTFB',
'domContentLoaded', 'pageLoadTime'
],
// 数据保留策略
retention: {
realTime: 24 * 60 * 60 * 1000, // 24小时实时数据
aggregated: 30 * 24 * 60 * 60 * 1000 // 30天聚合数据
}
};
// 性能监控服务
class PerformanceMonitoringService {
constructor(config = PerformanceConfig) {
this.config = config;
this.isEnabled = true;
this.metricsBuffer = [];
this.lastFlush = Date.now();
this.init();
}
init() {
// 初始化各种监控器
this.coreVitalsMonitor = new CoreWebVitalsMonitor();
this.customMonitor = new CustomPerformanceMonitor();
this.userMonitor = new UserExperienceMonitor();
// 设置定期刷新
setInterval(() => {
this.flushMetrics();
}, 30000); // 每30秒刷新一次
}
// 添加指标到缓冲区
addMetric(metric) {
if (!this.isEnabled) return;
this.metricsBuffer.push({
...metric,
timestamp: Date.now(),
sessionId: this.getSessionId()
});
// 如果缓冲区满了,立即刷新
if (this.metricsBuffer.length >= 50) {
this.flushMetrics();
}
}
// 刷新指标到服务器
flushMetrics() {
if (this.metricsBuffer.length === 0) return;
const batch = [...this.metricsBuffer];
this.metricsBuffer = [];
// 发送到服务器
if (navigator.sendBeacon) {
navigator.sendBeacon('/api/performance-batch', JSON.stringify(batch));
} else {
fetch('/api/performance-batch', {
method: 'POST',
body: JSON.stringify(batch),
keepalive: true
});
}
}
// 获取会话 ID
getSessionId() {
if (!sessionStorage.getItem('perf_session_id')) {
const sessionId = Math.random().toString(36).substr(2, 9) + Date.now().toString(36);
sessionStorage.setItem('perf_session_id', sessionId);
}
return sessionStorage.getItem('perf_session_id');
}
// 检查是否应该采样
shouldSample() {
return Math.random() < this.config.sampling.rate;
}
// 启用监控
enable() {
this.isEnabled = true;
}
// 禁用监控
disable() {
this.isEnabled = false;
}
// 获取性能统计
getStats() {
return {
bufferedMetrics: this.metricsBuffer.length,
config: this.config,
samplingRate: this.config.sampling.rate
};
}
}
// 初始化性能监控服务
const perfService = new PerformanceMonitoringService();
// 在页面加载完成后开始监控
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
if (perfService.shouldSample()) {
perfService.enable();
console.log('Performance monitoring started');
} else {
console.log('Performance monitoring skipped due to sampling');
}
});
} else {
if (perfService.shouldSample()) {
perfService.enable();
}
}
性能监控检查清单
- [ ] 实施 Core Web Vitals 监控
- [ ] 设置自定义性能指标
- [ ] 监控后端性能指标
- [ ] 跟踪用户行为和交互
- [ ] 实施适当的采样策略
- [ ] 设置性能阈值和警报
- [ ] 生成性能分析报告
- [ ] 实施数据保留策略
- [ ] 确保监控不影响性能
- [ ] 定期审查和优化监控策略
通过实施全面的性能监控,您可以及时发现性能问题并持续优化用户体验。