性能优化 API
浏览器提供的性能监控与优化相关 API
问题
浏览器提供了哪些性能优化相关的 API?如何使用它们进行性能监控和优化?
解答
1. Performance API
用于精确测量代码执行时间和获取页面性能指标。
// 高精度时间戳
const start = performance.now();
doSomething();
const end = performance.now();
console.log(`耗时: ${end - start}ms`);
// 性能标记
performance.mark('task-start');
doSomething();
performance.mark('task-end');
// 测量两个标记之间的时间
performance.measure('task-duration', 'task-start', 'task-end');
// 获取测量结果
const measures = performance.getEntriesByName('task-duration');
console.log(measures[0].duration);
// 获取页面加载性能数据
const timing = performance.getEntriesByType('navigation')[0];
console.log('DOM 解析完成:', timing.domContentLoadedEventEnd);
console.log('页面完全加载:', timing.loadEventEnd);
2. PerformanceObserver
异步观察性能条目,不阻塞主线程。
// 观察长任务(超过 50ms 的任务)
const longTaskObserver = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log('长任务检测:', entry.duration, 'ms');
}
});
longTaskObserver.observe({ entryTypes: ['longtask'] });
// 观察资源加载
const resourceObserver = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log(`${entry.name} 加载耗时: ${entry.duration}ms`);
}
});
resourceObserver.observe({ entryTypes: ['resource'] });
// 观察 LCP(最大内容绘制)
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'] });
3. requestAnimationFrame
在下一次重绘前执行回调,用于流畅动画。
// 平滑动画
function animate(element) {
let position = 0;
function step() {
position += 2;
element.style.transform = `translateX(${position}px)`;
if (position < 300) {
requestAnimationFrame(step);
}
}
requestAnimationFrame(step);
}
// 节流高频事件
let ticking = false;
window.addEventListener('scroll', () => {
if (!ticking) {
requestAnimationFrame(() => {
handleScroll();
ticking = false;
});
ticking = true;
}
});
4. requestIdleCallback
在浏览器空闲时执行低优先级任务。
// 空闲时执行任务
function processInIdle(tasks) {
function workLoop(deadline) {
// deadline.timeRemaining() 返回当前帧剩余时间
while (tasks.length > 0 && deadline.timeRemaining() > 0) {
const task = tasks.shift();
task();
}
if (tasks.length > 0) {
requestIdleCallback(workLoop);
}
}
requestIdleCallback(workLoop);
}
// 带超时的空闲回调
requestIdleCallback(
(deadline) => {
console.log('剩余时间:', deadline.timeRemaining());
console.log('是否超时:', deadline.didTimeout);
},
{ timeout: 2000 } // 最多等待 2 秒
);
5. Intersection Observer
观察元素与视口的交叉状态,用于懒加载。
// 图片懒加载
const lazyImages = document.querySelectorAll('img[data-src]');
const imageObserver = new IntersectionObserver(
(entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.removeAttribute('data-src');
observer.unobserve(img); // 加载后停止观察
}
});
},
{
rootMargin: '100px', // 提前 100px 加载
threshold: 0.1
}
);
lazyImages.forEach((img) => imageObserver.observe(img));
// 无限滚动
const sentinel = document.querySelector('#sentinel');
const scrollObserver = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting) {
loadMoreContent();
}
});
scrollObserver.observe(sentinel);
6. Web Vitals 测量
// 测量 FCP(首次内容绘制)
new PerformanceObserver((list) => {
const entry = list.getEntries()[0];
console.log('FCP:', entry.startTime);
}).observe({ entryTypes: ['paint'] });
// 测量 FID(首次输入延迟)
new PerformanceObserver((list) => {
const entry = list.getEntries()[0];
console.log('FID:', entry.processingStart - entry.startTime);
}).observe({ entryTypes: ['first-input'] });
// 测量 CLS(累积布局偏移)
let clsScore = 0;
new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (!entry.hadRecentInput) {
clsScore += entry.value;
}
}
console.log('CLS:', clsScore);
}).observe({ entryTypes: ['layout-shift'] });
关键点
- Performance API:
performance.now()提供微秒级精度,mark/measure用于标记和测量代码段 - PerformanceObserver:异步观察性能条目,支持 longtask、resource、paint 等类型
- requestAnimationFrame:与屏幕刷新率同步,适合动画和高频事件节流
- requestIdleCallback:利用浏览器空闲时间执行低优先级任务,避免阻塞用户交互
- Intersection Observer:高效检测元素可见性,替代 scroll 事件监听实现懒加载
目录