性能优化 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 APIperformance.now() 提供微秒级精度,mark/measure 用于标记和测量代码段
  • PerformanceObserver:异步观察性能条目,支持 longtask、resource、paint 等类型
  • requestAnimationFrame:与屏幕刷新率同步,适合动画和高频事件节流
  • requestIdleCallback:利用浏览器空闲时间执行低优先级任务,避免阻塞用户交互
  • Intersection Observer:高效检测元素可见性,替代 scroll 事件监听实现懒加载