核心理念
渐进式性能监控基于分层体验和阶段化加载的思想,将应用的生命周期分解为多个关键阶段,为每个阶段建立独立的监控指标,从而全面反映用户体验的递进过程。
关键监控阶段与指标
1. 核心内容加载阶段
目标:监控用户感知到”内容已加载”的关键时刻
// 标记核心内容加载
class CoreContentMetrics {
constructor() {
this.observedElements = new Set();
}
// 监控关键内容元素可见性
observeCriticalElements() {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const element = entry.target;
const metric = {
type: 'critical_element_visible',
element: element.tagName,
id: element.id || 'unknown',
timestamp: Date.now(),
timeToVisible: performance.now()
};
this.reportMetric(metric);
observer.unobserve(element);
}
});
}, { threshold: 0.1 });
// 观察关键内容元素
document.querySelectorAll('[data-critical]').forEach(el => {
observer.observe(el);
});
}
// 标记核心内容完成
markCoreContentLoaded() {
performance.mark('core_content_loaded');
// 计算核心内容加载时间
const navStart = performance.getEntriesByType('navigation')[0]?.fetchStart || 0;
const coreContentTime = performance.now() - navStart;
this.reportMetric({
type: 'core_content_complete',
duration: coreContentTime,
timestamp: Date.now()
});
}
}2. 视觉稳定阶段
目标:监控布局偏移和视觉稳定性
class VisualStabilityMetrics {
constructor() {
this.cls = 0;
this.clsObserver = null;
}
// 监控累积布局偏移 (CLS)
monitorLayoutShifts() {
let sessionValue = 0;
let sessionEntries = [];
this.clsObserver = new PerformanceObserver((list) => {
list.getEntries().forEach(entry => {
// 只计算没有用户输入的布局偏移
if (!entry.hadRecentInput) {
sessionEntries.push(entry);
sessionValue += entry.value;
this.reportMetric({
type: 'layout_shift',
value: entry.value,
cumulative: sessionValue,
element: entry.sources?.[0]?.node?.toString() || 'unknown'
});
}
});
});
this.clsObserver.observe({
type: 'layout-shift',
buffered: true
});
// 页面隐藏时报告最终 CLS
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') {
this.reportMetric({
type: 'final_cls',
value: sessionValue,
entries: sessionEntries.length
});
}
});
}
// 监控图片加载导致的布局偏移
monitorImageLoading() {
const images = document.querySelectorAll('img');
images.forEach(img => {
if (!img.complete) {
img.addEventListener('load', () => {
this.checkLayoutImpact(img);
});
}
});
}
}3. 交互准备阶段
目标:监控应用何时变得可交互
class InteractionReadinessMetrics {
constructor() {
this.longTasks = [];
this.firstInputDelay = null;
}
// 监控长任务
monitorLongTasks() {
const observer = new PerformanceObserver((list) => {
list.getEntries().forEach(entry => {
this.longTasks.push(entry);
this.reportMetric({
type: 'long_task',
duration: entry.duration,
startTime: entry.startTime,
context: entry.attribution?.[0]?.containerType || 'unknown'
});
});
});
observer.observe({
entryTypes: ['longtask']
});
}
// 监控首次输入延迟 (FID)
monitorFirstInput() {
const observer = new PerformanceObserver((list) => {
list.getEntries().forEach(entry => {
if (!this.firstInputDelay) {
this.firstInputDelay = entry;
this.reportMetric({
type: 'first_input_delay',
delay: entry.processingStart - entry.startTime,
duration: entry.duration,
interactionType: entry.name
});
}
});
});
observer.observe({
type: 'first-input',
buffered: true
});
}
// 计算可交互时间 (TTI)
calculateTimeToInteractive() {
const longTaskThreshold = 50; // ms
const quietWindow = 5000; // 5 seconds
let lastLongTaskEnd = 0;
let tti = null;
this.longTasks.forEach(task => {
if (task.duration > longTaskThreshold) {
lastLongTaskEnd = Math.max(lastLongTaskEnd, task.startTime + task.duration);
}
});
if (lastLongTaskEnd > 0) {
tti = lastLongTaskEnd + quietWindow;
}
return tti;
}
}4. 增强功能加载阶段
目标:监控非关键资源和功能的加载情况
class EnhancementMetrics {
constructor() {
this.enhancements = new Map();
}
// 监控代码分割组件的加载
monitorCodeSplitting() {
const originalImport = window.import;
window.import = function(chunkName) {
const startTime = performance.now();
return originalImport.apply(this, arguments)
.then(module => {
const loadTime = performance.now() - startTime;
this.reportMetric({
type: 'chunk_loaded',
name: chunkName,
duration: loadTime,
size: this.estimateChunkSize(module),
timestamp: Date.now()
});
return module;
})
.catch(error => {
this.reportMetric({
type: 'chunk_load_error',
name: chunkName,
error: error.message,
timestamp: Date.now()
});
throw error;
});
};
}
// 监控第三方脚本加载
monitorThirdPartyResources() {
const observer = new PerformanceObserver((list) => {
list.getEntries().forEach(entry => {
if (this.isThirdParty(entry.name)) {
this.reportMetric({
type: 'third_party_resource',
name: this.extractDomain(entry.name),
duration: entry.duration,
size: entry.transferSize,
cached: entry.transferSize === 0
});
}
});
});
observer.observe({
entryTypes: ['resource']
});
}
// 监控组件级渲染性能
monitorComponentRender(componentName) {
const startMark = `${componentName}_render_start`;
const endMark = `${componentName}_render_end`;
performance.mark(startMark);
return {
end: () => {
performance.mark(endMark);
const measure = performance.measure(
`${componentName}_render`,
startMark,
endMark
);
this.reportMetric({
type: 'component_render',
name: componentName,
duration: measure.duration,
timestamp: Date.now()
});
}
};
}
}5. 运行时性能阶段
目标:监控应用运行时的性能表现
class RuntimePerformanceMetrics {
constructor() {
this.fps = 0;
this.frameCount = 0;
this.lastTime = performance.now();
}
// 监控帧率 (FPS)
monitorFPS() {
const calculateFPS = (now) => {
this.frameCount++;
if (now >= this.lastTime + 1000) {
this.fps = Math.round((this.frameCount * 1000) / (now - this.lastTime));
this.reportMetric({
type: 'fps',
value: this.fps,
timestamp: now
});
this.frameCount = 0;
this.lastTime = now;
}
requestAnimationFrame(calculateFPS);
};
requestAnimationFrame(calculateFPS);
}
// 监控内存使用
monitorMemory() {
if (performance.memory) {
setInterval(() => {
const memory = performance.memory;
this.reportMetric({
type: 'memory_usage',
used: memory.usedJSHeapSize,
total: memory.totalJSHeapSize,
limit: memory.jsHeapSizeLimit,
timestamp: Date.now()
});
}, 30000); // 每30秒报告一次
}
}
// 监控网络状态变化
monitorNetworkConditions() {
if (navigator.connection) {
const connection = navigator.connection;
connection.addEventListener('change', () => {
this.reportMetric({
type: 'network_change',
effectiveType: connection.effectiveType,
downlink: connection.downlink,
rtt: connection.rtt,
timestamp: Date.now()
});
});
}
}
}完整的监控系统集成
class ProgressivePerformanceMonitor {
constructor() {
this.metrics = [];
this.reportUrl = '/api/performance-metrics';
// 初始化各阶段监控
this.coreMetrics = new CoreContentMetrics();
this.visualMetrics = new VisualStabilityMetrics();
this.interactionMetrics = new InteractionReadinessMetrics();
this.enhancementMetrics = new EnhancementMetrics();
this.runtimeMetrics = new RuntimePerformanceMetrics();
this.setupGlobalErrorHandling();
}
// 启动所有监控
start() {
// 核心内容监控
this.coreMetrics.observeCriticalElements();
// 视觉稳定性监控
this.visualMetrics.monitorLayoutShifts();
this.visualMetrics.monitorImageLoading();
// 交互准备监控
this.interactionMetrics.monitorLongTasks();
this.interactionMetrics.monitorFirstInput();
// 增强功能监控
this.enhancementMetrics.monitorCodeSplitting();
this.enhancementMetrics.monitorThirdPartyResources();
// 运行时监控
this.runtimeMetrics.monitorFPS();
this.runtimeMetrics.monitorMemory();
this.runtimeMetrics.monitorNetworkConditions();
// 标记各阶段完成
this.markProgressivePhases();
}
// 标记渐进式阶段完成
markProgressivePhases() {
window.addEventListener('load', () => {
this.coreMetrics.markCoreContentLoaded();
// 延迟标记增强完成,等待关键用户交互准备就绪
setTimeout(() => {
this.reportMetric({
type: 'enhancements_ready',
timestamp: Date.now(),
tti: this.interactionMetrics.calculateTimeToInteractive()
});
}, 1000);
});
}
// 报告指标
reportMetric(metric) {
// 添加上下文信息
const enrichedMetric = {
...metric,
sessionId: this.getSessionId(),
url: window.location.href,
userAgent: navigator.userAgent,
timestamp: metric.timestamp || Date.now()
};
this.metrics.push(enrichedMetric);
// 批量报告
if (this.metrics.length >= 10) {
this.flushMetrics();
}
}
// 批量发送指标
flushMetrics() {
if (this.metrics.length === 0) return;
const metricsToSend = [...this.metrics];
this.metrics = [];
// 使用 sendBeacon 确保在页面卸载时也能发送
if (navigator.sendBeacon) {
navigator.sendBeacon(
this.reportUrl,
JSON.stringify(metricsToSend)
);
} else {
// 回退到 fetch
fetch(this.reportUrl, {
method: 'POST',
body: JSON.stringify(metricsToSend),
keepalive: true
});
}
}
// 设置全局错误处理
setupGlobalErrorHandling() {
window.addEventListener('error', (event) => {
this.reportMetric({
type: 'global_error',
message: event.message,
filename: event.filename,
lineno: event.lineno,
colno: event.colno,
error: event.error?.toString()
});
});
window.addEventListener('unhandledrejection', (event) => {
this.reportMetric({
type: 'unhandled_rejection',
reason: event.reason?.toString()
});
});
}
getSessionId() {
if (!this.sessionId) {
this.sessionId = 'session_' + Math.random().toString(36).substr(2, 9);
}
return this.sessionId;
}
}
// 使用示例
const monitor = new ProgressivePerformanceMonitor();
monitor.start();
// 在页面卸载前刷新所有指标
window.addEventListener('beforeunload', () => {
monitor.flushMetrics();
});监控数据分析与告警
class PerformanceAnalytics {
constructor() {
this.thresholds = {
core_content: 3000, // 3秒
first_paint: 2000, // 2秒
first_input_delay: 100, // 100ms
layout_shift: 0.1, // CLS 阈值
long_task: 50, // 50ms
fps: 30 // 30帧
};
}
// 分析性能数据并生成告警
analyzeMetrics(metrics) {
const alerts = [];
metrics.forEach(metric => {
switch (metric.type) {
case 'core_content_complete':
if (metric.duration > this.thresholds.core_content) {
alerts.push(this.createAlert('slow_core_content', metric));
}
break;
case 'first_input_delay':
if (metric.delay > this.thresholds.first_input_delay) {
alerts.push(this.createAlert('high_input_delay', metric));
}
break;
case 'layout_shift':
if (metric.cumulative > this.thresholds.layout_shift) {
alerts.push(this.createAlert('high_layout_shift', metric));
}
break;
case 'long_task':
if (metric.duration > this.thresholds.long_task) {
alerts.push(this.createAlert('long_task_detected', metric));
}
break;
case 'fps':
if (metric.value < this.thresholds.fps) {
alerts.push(this.createAlert('low_fps', metric));
}
break;
}
});
return alerts;
}
createAlert(type, metric) {
return {
type,
severity: this.getAlertSeverity(type),
metric,
timestamp: Date.now(),
message: this.getAlertMessage(type, metric)
};
}
getAlertSeverity(alertType) {
const severityMap = {
'slow_core_content': 'high',
'high_input_delay': 'medium',
'high_layout_shift': 'medium',
'long_task_detected': 'low',
'low_fps': 'medium'
};
return severityMap[alertType] || 'low';
}
}总结
渐进式性能监控的核心价值在于:
- 分层监控:对应渐进式加载的每个阶段,提供精准的性能洞察
- 用户体验导向:关注用户真实感知的指标,而非单纯的技术指标
- 上下文丰富:结合业务场景,理解不同功能对用户的价值差异
- 主动预警:基于阈值分析,在问题影响用户前发现并解决
- 持续优化:为性能优化提供数据支撑和效果验证
这种监控方式确保了我们在追求功能丰富性的同时,始终保持对用户体验的高度关注,真正实现了”渐进增强”的性能维度实践。