PerformanceObserver API
#前端性能
目录
- 1. 总结
- 2. PerformanceObserver 概述
- 3. 基本使用方法
- 4. 可观察的性能指标类型
- 5. 实际应用示例
- 6. 自定义性能标记
- 7. 错误处理和断开连接
- 8. 性能数据收集和分析
1. 总结
- new PerformanceObserver:
- 以==异步==的方式监听性能度量事件,而==不会阻塞主线程==
- CLS (Cumulative Layout Shift) 统计
- 检测 layout-shift,==并且需要累加==
- 可自定义性能标记
2. PerformanceObserver 概述
- PerformanceObserver 是 Performance API 的一部分,用于观察和响应性能相关的事件。
- 通过 PerformanceObserver,我们可以全面监控网页性能,收集各种性能指标,为性能优化提供数据支持。
- 允许我们以异步的方式监听性能度量事件,而不会阻塞主线程。
3. 基本使用方法
// 创建性能观察器
const observer = new PerformanceObserver((list, observer) => {
// 获取所有性能条目
const entries = list.getEntries();
entries.forEach(entry => {
console.log('Performance Entry:', entry);
});
});
// 开始观察特定类型的性能条目
observer.observe({
entryTypes: ['paint', 'largest-contentful-paint', 'layout-shift']
});
4. 可观察的性能指标类型
// 常用的 entryTypes
const entryTypes = [
'navigation', // 导航计时
'resource', // 资源加载
'paint', // 绘制时间点
'mark', // 自定义性能标记
'measure', // 自定义性能测量
'layout-shift', // 布局偏移
'largest-contentful-paint', // 最大内容绘制
'first-input', // 首次输入延迟
'element' // 元素计时
];
5. 实际应用示例
5.1. 监控页面加载性能
const pageLoadObserver = new PerformanceObserver((list) => {
const entries = list.getEntries();
entries.forEach(entry => {
// 导航计时数据
if (entry.entryType === 'navigation') {
console.log({
DNS查询时间: entry.domainLookupEnd - entry.domainLookupStart,
TCP连接时间: entry.connectEnd - entry.connectStart,
页面加载总时间: entry.loadEventEnd - entry.startTime
});
}
});
});
pageLoadObserver.observe({ entryTypes: ['navigation'] });
5.2. 监控资源加载
const resourceObserver = new PerformanceObserver((list) => {
list.getEntries().forEach(entry => {
// 资源加载详情
console.log({
资源名称: entry.name,
资源类型: entry.initiatorType,
加载时间: entry.duration,
传输大小: entry.transferSize,
开始时间: entry.startTime
});
});
});
resourceObserver.observe({ entryTypes: ['resource'] });
5.3. 监控 Core Web Vitals
// LCP (Largest Contentful Paint) 监控
const lcpObserver = new PerformanceObserver((list) => {
const entries = list.getEntries();
const lastEntry = entries[entries.length - 1];
console.log('LCP:', lastEntry.startTime);
});
lcpObserver.observe({ entryTypes: ['largest-contentful-paint'] });
// 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('Current CLS:', clsValue);
});
clsObserver.observe({ entryTypes: ['layout-shift'] });
6. 自定义性能标记
// 创建自定义性能标记
performance.mark('customStart');
// 某些操作
setTimeout(() => {
performance.mark('customEnd');
// 测量两个标记之间的时间
performance.measure('customOperation', 'customStart', 'customEnd');
// 观察测量结果
const measureObserver = new PerformanceObserver((list) => {
const measures = list.getEntries();
measures.forEach(measure => {
console.log(`${measure.name} took ${measure.duration}ms`);
});
});
measureObserver.observe({ entryTypes: ['measure'] });
}, 1000);
7. 错误处理和断开连接
const observer = new PerformanceObserver((list, observer) => {
try {
const entries = list.getEntries();
// 处理条目...
// 可选:在特定条件下断开观察
if (someCondition) {
observer.disconnect();
}
} catch (error) {
console.error('Performance observation error:', error);
}
});
// 错误处理
try {
observer.observe({
entryTypes: ['paint'],
buffered: true // 获取缓冲的条目
});
} catch (error) {
console.error('Failed to start observer:', error);
}
8. 性能数据收集和分析
// 创建性能数据收集器
class PerformanceCollector {
constructor() {
this.metrics = {
navigation: [],
resource: [],
paint: []
};
this.initObservers();
}
initObservers() {
// 导航性能
new PerformanceObserver((list) => {
this.metrics.navigation = list.getEntries();
this.analyzeNavigation();
}).observe({ entryTypes: ['navigation'] });
// 资源性能
new PerformanceObserver((list) => {
this.metrics.resource = [...this.metrics.resource, ...list.getEntries()];
this.analyzeResources();
}).observe({ entryTypes: ['resource'] });
// 绘制性能
new PerformanceObserver((list) => {
this.metrics.paint = list.getEntries();
this.analyzePaint();
}).observe({ entryTypes: ['paint'] });
}
analyzeNavigation() {
const navEntry = this.metrics.navigation[0];
if (navEntry) {
console.log({
FCP: navEntry.firstContentfulPaint,
DOMContentLoaded: navEntry.domContentLoadedEventEnd - navEntry.domContentLoadedEventStart,
LoadComplete: navEntry.loadEventEnd - navEntry.startTime
});
}
}
analyzeResources() {
const slowResources = this.metrics.resource
.filter(entry => entry.duration > 1000)
.map(entry => ({
url: entry.name,
duration: entry.duration,
size: entry.transferSize
}));
console.log('Slow Resources:', slowResources);
}
analyzePaint() {
const paintMetrics = this.metrics.paint.reduce((acc, entry) => {
acc[entry.name] = entry.startTime;
return acc;
}, {});
console.log('Paint Metrics:', paintMetrics);
}
}
// 使用收集器
const collector = new PerformanceCollector();