JavaScript性能监控系统详解 📊
今天,让我们深入探讨JavaScript的性能监控系统。性能监控对于保证应用的稳定性和用户体验至关重要。
性能监控基础概念 🌟
💡 小知识:JavaScript性能监控是指通过收集和分析各种性能指标,来评估和优化应用性能的过程。这包括页面加载时间、资源使用情况、运行时性能等多个方面。
性能指标收集 📈
// 1. 性能指标收集器
class PerformanceCollector {
constructor() {
this.metrics = new Map();
this.observers = new Set();
}
// 收集页面加载性能
collectPageMetrics() {
const timing = performance.timing;
const metrics = {
dnsTime: timing.domainLookupEnd - timing.domainLookupStart,
tcpTime: timing.connectEnd - timing.connectStart,
ttfb: timing.responseStart - timing.requestStart,
domReady: timing.domContentLoadedEventEnd - timing.navigationStart,
loadComplete: timing.loadEventEnd - timing.navigationStart
};
this.metrics.set('page', metrics);
this.notifyObservers('page', metrics);
}
// 收集资源加载性能
collectResourceMetrics() {
const resources = performance.getEntriesByType('resource');
const metrics = resources.map(resource => ({
name: resource.name,
type: resource.initiatorType,
duration: resource.duration,
size: resource.transferSize,
startTime: resource.startTime
}));
this.metrics.set('resources', metrics);
this.notifyObservers('resources', metrics);
}
// 收集运行时性能
collectRuntimeMetrics() {
const metrics = {
memory: performance.memory ? {
usedJSHeapSize: performance.memory.usedJSHeapSize,
totalJSHeapSize: performance.memory.totalJSHeapSize,
jsHeapSizeLimit: performance.memory.jsHeapSizeLimit
} : null,
fps: this.calculateFPS()
};
this.metrics.set('runtime', metrics);
this.notifyObservers('runtime', metrics);
}
calculateFPS() {
let lastTime = performance.now();
let frames = 0;
let fps = 0;
const updateFPS = () => {
const now = performance.now();
frames++;
if (now > lastTime + 1000) {
fps = Math.round((frames * 1000) / (now - lastTime));
frames = 0;
lastTime = now;
}
requestAnimationFrame(updateFPS);
};
requestAnimationFrame(updateFPS);
return () => fps;
}
addObserver(observer) {
this.observers.add(observer);
}
removeObserver(observer) {
this.observers.delete(observer);
}
notifyObservers(type, data) {
this.observers.forEach(observer => {
observer.update(type, data);
});
}
}
// 2. 性能标记管理器
class PerformanceMarker {
constructor() {
this.marks = new Map();
}
mark(name) {
performance.mark(name);
this.marks.set(name, performance.now());
}
measure(name, startMark, endMark) {
performance.measure(name, startMark, endMark);
const measure = performance.getEntriesByName(name, 'measure')[0];
return {
name,
duration: measure.duration,
startTime: measure.startTime
};
}
clearMarks() {
performance.clearMarks();
this.marks.clear();
}
clearMeasures() {
performance.clearMeasures();
}
}
// 3. 用户交互监控
class InteractionMonitor {
constructor() {
this.interactions = [];
this.setupListeners();
}
setupListeners() {
const observer = new PerformanceObserver(list => {
const entries = list.getEntries();
this.processInteractions(entries);
});
observer.observe({
entryTypes: ['first-input', 'layout-shift', 'largest-contentful-paint']
});
}
processInteractions(entries) {
entries.forEach(entry => {
this.interactions.push({
type: entry.entryType,
startTime: entry.startTime,
duration: entry.duration,
value: entry.value,
element: entry.target
});
});
}
getInteractionMetrics() {
return {
fid: this.calculateFID(),
cls: this.calculateCLS(),
lcp: this.calculateLCP()
};
}
calculateFID() {
const fidEntry = this.interactions.find(
i => i.type === 'first-input'
);
return fidEntry ? fidEntry.duration : null;
}
calculateCLS() {
return this.interactions
.filter(i => i.type === 'layout-shift')
.reduce((sum, entry) => sum + entry.value, 0);
}
calculateLCP() {
const lcpEntries = this.interactions
.filter(i => i.type === 'largest-contentful-paint');
return lcpEntries.length > 0
? lcpEntries[lcpEntries.length - 1].startTime
: null;
}
}
性能分析工具 🔍
// 1. 性能分析器
class PerformanceAnalyzer {
constructor() {
this.thresholds = new Map();
this.issues = [];
}
setThreshold(metric, value) {
this.thresholds.set(metric, value);
}
analyzeMetrics(metrics) {
this.issues = [];
// 分析页面加载性能
if (metrics.page) {
this.analyzePageMetrics(metrics.page);
}
// 分析资源加载性能
if (metrics.resources) {
this.analyzeResourceMetrics(metrics.resources);
}
// 分析运行时性能
if (metrics.runtime) {
this.analyzeRuntimeMetrics(metrics.runtime);
}
return this.issues;
}
analyzePageMetrics(pageMetrics) {
if (pageMetrics.ttfb > this.thresholds.get('ttfb')) {
this.issues.push({
type: 'warning',
metric: 'ttfb',
message: 'Time to First Byte is too high',
value: pageMetrics.ttfb,
threshold: this.thresholds.get('ttfb')
});
}
if (pageMetrics.domReady > this.thresholds.get('domReady')) {
this.issues.push({
type: 'error',
metric: 'domReady',
message: 'DOM Ready time is too high',
value: pageMetrics.domReady,
threshold: this.thresholds.get('domReady')
});
}
}
analyzeResourceMetrics(resources) {
const largeResources = resources.filter(
r => r.size > this.thresholds.get('resourceSize')
);
if (largeResources.length > 0) {
this.issues.push({
type: 'warning',
metric: 'resourceSize',
message: 'Large resources detected',
resources: largeResources
});
}
}
analyzeRuntimeMetrics(runtime) {
if (runtime.memory &&
runtime.memory.usedJSHeapSize >
this.thresholds.get('heapSize')) {
this.issues.push({
type: 'warning',
metric: 'memory',
message: 'High memory usage detected',
value: runtime.memory.usedJSHeapSize
});
}
if (runtime.fps() < this.thresholds.get('fps')) {
this.issues.push({
type: 'error',
metric: 'fps',
message: 'Low FPS detected',
value: runtime.fps()
});
}
}
generateReport() {
return {
timestamp: new Date(),
issueCount: this.issues.length,
criticalIssues: this.issues.filter(i => i.type === 'error'),
warnings: this.issues.filter(i => i.type === 'warning'),
recommendations: this.generateRecommendations()
};
}
generateRecommendations() {
return this.issues.map(issue => {
switch (issue.metric) {
case 'ttfb':
return 'Consider using a CDN or optimizing server response time';
case 'domReady':
return 'Optimize JavaScript execution and reduce blocking resources';
case 'resourceSize':
return 'Compress and optimize large resources';
case 'memory':
return 'Check for memory leaks and optimize memory usage';
case 'fps':
return 'Optimize animations and reduce DOM operations';
default:
return 'Review and optimize the affected area';
}
});
}
}
// 2. 性能监控仪表板
class PerformanceDashboard {
constructor() {
this.metrics = [];
this.charts = new Map();
}
addMetric(metric) {
this.metrics.push({
...metric,
timestamp: new Date()
});
this.updateCharts();
}
createChart(type, data) {
// 实现图表创建逻辑
return {
type,
data,
render: () => {
// 渲染图表
}
};
}
updateCharts() {
// 更新页面加载时间趋势
this.charts.set('loadTime', this.createChart(
'line',
this.metrics.map(m => ({
x: m.timestamp,
y: m.page.loadComplete
}))
));
// 更新资源使用趋势
this.charts.set('resources', this.createChart(
'bar',
this.metrics.map(m => ({
x: m.timestamp,
y: m.resources.length
}))
));
// 更新内存使用趋势
this.charts.set('memory', this.createChart(
'area',
this.metrics.map(m => ({
x: m.timestamp,
y: m.runtime.memory?.usedJSHeapSize
}))
));
}
generateReport(timeRange) {
const filteredMetrics = this.metrics.filter(
m => m.timestamp >= timeRange.start &&
m.timestamp <= timeRange.end
);
return {
summary: this.calculateSummary(filteredMetrics),
trends: this.calculateTrends(filteredMetrics),
issues: this.findIssues(filteredMetrics)
};
}
}
// 3. 性能优化建议生成器
class OptimizationAdvisor {
constructor() {
this.rules = new Map();
}
addRule(name, condition, recommendation) {
this.rules.set(name, { condition, recommendation });
}
analyze(metrics) {
const recommendations = [];
for (const [name, rule] of this.rules) {
if (rule.condition(metrics)) {
recommendations.push({
name,
recommendation: rule.recommendation,
priority: this.calculatePriority(metrics, name)
});
}
}
return recommendations.sort((a, b) => b.priority - a.priority);
}
calculatePriority(metrics, ruleName) {
// 根据性能指标的严重程度计算优化建议的优先级
const weights = {
loadTime: 0.3,
memory: 0.2,
fps: 0.3,
resources: 0.2
};
let score = 0;
if (metrics.page?.loadComplete > 3000) {
score += weights.loadTime;
}
if (metrics.runtime?.memory?.usedJSHeapSize >
metrics.runtime?.memory?.jsHeapSizeLimit * 0.8) {
score += weights.memory;
}
if (metrics.runtime?.fps() < 30) {
score += weights.fps;
}
if (metrics.resources?.length > 50) {
score += weights.resources;
}
return score;
}
}
报警和通知系统 🚨
// 1. 报警管理器
class AlertManager {
constructor() {
this.alerts = new Map();
this.handlers = new Map();
}
addAlert(name, condition, options = {}) {
this.alerts.set(name, {
condition,
threshold: options.threshold,
cooldown: options.cooldown || 5 * 60 * 1000, // 5分钟
lastTriggered: 0,
status: 'inactive'
});
}
addHandler(severity, handler) {
if (!this.handlers.has(severity)) {
this.handlers.set(severity, []);
}
this.handlers.get(severity).push(handler);
}
checkAlerts(metrics) {
const now = Date.now();
const triggeredAlerts = [];
for (const [name, alert] of this.alerts) {
if (alert.status === 'inactive' &&
now - alert.lastTriggered > alert.cooldown) {
if (alert.condition(metrics)) {
alert.status = 'active';
alert.lastTriggered = now;
triggeredAlerts.push(name);
}
}
}
return triggeredAlerts;
}
async notify(alertName, data) {
const alert = this.alerts.get(alertName);
if (!alert) return;
const handlers = this.handlers.get(alert.severity) || [];
await Promise.all(
handlers.map(handler => handler(alertName, data))
);
}
}
// 2. 通知发送器
class NotificationSender {
constructor() {
this.channels = new Map();
}
addChannel(name, sender) {
this.channels.set(name, sender);
}
async send(channel, message) {
const sender = this.channels.get(channel);
if (!sender) {
throw new Error(`Channel ${channel} not found`);
}
try {
await sender(message);
} catch (error) {
console.error(`Failed to send notification to ${channel}:`, error);
throw error;
}
}
async broadcast(message) {
const results = await Promise.allSettled(
Array.from(this.channels.entries())
.map(([channel, sender]) => this.send(channel, message))
);
return results.reduce((summary, result, index) => {
const channel = Array.from(this.channels.keys())[index];
summary[channel] = result.status === 'fulfilled';
return summary;
}, {});
}
}
// 3. 报告生成器
class ReportGenerator {
constructor() {
this.templates = new Map();
}
addTemplate(name, template) {
this.templates.set(name, template);
}
generateReport(data, templateName = 'default') {
const template = this.templates.get(templateName);
if (!template) {
throw new Error(`Template ${templateName} not found`);
}
return template(data);
}
async saveReport(report, format = 'json') {
const fileName = `performance-report-${new Date().toISOString()}.${format}`;
switch (format) {
case 'json':
await fs.writeFile(fileName, JSON.stringify(report, null, 2));
break;
case 'html':
await fs.writeFile(fileName, this.generateHtmlReport(report));
break;
case 'pdf':
await this.generatePdfReport(report, fileName);
break;
default:
throw new Error(`Unsupported format: ${format}`);
}
return fileName;
}
generateHtmlReport(report) {
// 生成HTML格式的报告
return `
<!DOCTYPE html>
<html>
<head>
<title>Performance Report</title>
</head>
<body>
<h1>Performance Report</h1>
<div class="metrics">
${this.renderMetrics(report.metrics)}
</div>
<div class="issues">
${this.renderIssues(report.issues)}
</div>
<div class="recommendations">
${this.renderRecommendations(report.recommendations)}
</div>
</body>
</html>
`;
}
}
最佳实践建议 💡
- 性能监控策略
// 1. 性能预算管理器
class PerformanceBudgetManager {
constructor() {
this.budgets = new Map();
}
setBudget(metric, limit) {
this.budgets.set(metric, limit);
}
checkBudget(metric, value) {
const limit = this.budgets.get(metric);
if (!limit) return true;
return value <= limit;
}
generateBudgetReport(metrics) {
const report = {
timestamp: new Date(),
violations: [],
status: 'pass'
};
for (const [metric, limit] of this.budgets) {
const value = metrics[metric];
if (value > limit) {
report.violations.push({
metric,
limit,
value,
overage: value - limit
});
report.status = 'fail';
}
}
return report;
}
}
// 2. 性能监控配置管理器
class MonitoringConfigManager {
constructor() {
this.config = {
sampleRate: 0.1,
metrics: new Set(),
alertThresholds: new Map()
};
}
setSampleRate(rate) {
if (rate < 0 || rate > 1) {
throw new Error('Sample rate must be between 0 and 1');
}
this.config.sampleRate = rate;
}
enableMetric(metric) {
this.config.metrics.add(metric);
}
disableMetric(metric) {
this.config.metrics.delete(metric);
}
setAlertThreshold(metric, threshold) {
this.config.alertThresholds.set(metric, threshold);
}
shouldCollect() {
return Math.random() < this.config.sampleRate;
}
}
// 3. 性能数据存储管理器
class MetricsStorageManager {
constructor() {
this.storage = new Map();
this.retention = 30 * 24 * 60 * 60 * 1000; // 30天
}
store(metrics) {
const timestamp = Date.now();
this.storage.set(timestamp, metrics);
this.cleanup();
}
cleanup() {
const cutoff = Date.now() - this.retention;
for (const [timestamp] of this.storage) {
if (timestamp < cutoff) {
this.storage.delete(timestamp);
}
}
}
query(timeRange) {
const results = [];
for (const [timestamp, metrics] of this.storage) {
if (timestamp >= timeRange.start &&
timestamp <= timeRange.end) {
results.push({ timestamp, metrics });
}
}
return results;
}
}
结语 📝
JavaScript性能监控系统是保证应用性能和用户体验的关键工具。通过本文,我们学习了:
- 性能指标的收集和分析
- 性能监控工具的实现
- 报警和通知系统的构建
- 性能报告的生成
- 最佳实践和优化建议
💡 学习建议:在实施性能监控时,要注意平衡监控的全面性和系统性能的开销。选择合适的采样率和监控指标,避免监控系统本身成为性能瓶颈。同时,要建立完善的报警机制和响应流程,确保能够及时发现和解决性能问题。
如果你觉得这篇文章有帮助,欢迎点赞收藏,也期待在评论区看到你的想法和建议!👇
终身学习,共同成长。
咱们下一期见
💻