浏览器中的 Observer API 详解
浏览器提供了多种 Observer(观察者)API,用于异步监听 DOM 变化、元素可见性、性能指标等场景。以下是主流 Observer 的分类与核心用法:
- MutationObserver 功能:监听 DOM 树的结构或属性变化。
典型场景:
- 防止水印被移除
- 动态内容加载(如无限滚动列表)
- 第三方插件侵入性修改监控
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'childList') {
console.log('子节点变化:', mutation.addedNodes);
} else if (mutation.type === 'attributes') {
console.log('属性变化:', mutation.attributeName);
}
});
});
// 配置监听选项
observer.observe(document.body, {
attributes: true, // 监听属性变化
childList: true, // 监听子节点增删
subtree: true // 递归监听所有后代节点
});
// 停止监听
// observer.disconnect();
复制代码
- IntersectionObserver 功能:监听元素与视口(或指定容器)的交叉状态。
典型场景:
- 图片/组件懒加载
- 广告曝光统计
- 滚动动画触发
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
console.log('元素进入视口:', entry.target);
entry.target.src = entry.target.dataset.src; // 懒加载图片
observer.unobserve(entry.target); // 仅触发一次
}
});
}, {
root: null, // 默认视口
rootMargin: '0px', // 视口边界扩展
threshold: 0.5 // 触发阈值(50%可见)
});
// 监听目标元素
document.querySelectorAll('.lazy-img').forEach(img => {
observer.observe(img);
});
复制代码
- ResizeObserver 功能:监听元素尺寸变化(包括
display: none的元素)。
典型场景:
- 响应式布局调整
- Canvas/图表自适应容器
- 动态内容高度计算
const observer = new ResizeObserver((entries) => {
entries.forEach(entry => {
const { width, height } = entry.contentRect;
console.log('元素尺寸变化:', width, height);
});
});
// 监听指定元素
observer.observe(document.getElementById('resizable-box'));
复制代码
- PerformanceObserver 功能:监听性能指标(如资源加载时长、长任务等)。
典型场景:
- 页面性能监控与优化
- 关键资源加载耗时统计
- 用户行为性能分析
const observer = new PerformanceObserver((list) => {
list.getEntries().forEach(entry => {
if (entry.entryType === 'resource') {
console.log('资源加载耗时:', entry.name, entry.duration);
}
});
});
// 监听资源加载性能条目
observer.observe({ entryTypes: ['resource', 'longtask'] });
复制代码
- ReportingObserver 功能:监听浏览器生成的报告(如废弃 API 警告、安全策略违规)。
典型场景:
- 废弃 API 使用监控
- CSP(内容安全策略)违规日志收集
const observer = new ReportingObserver((reports) => {
reports.forEach(report => {
console.log('报告类型:', report.type);
console.log('违规内容:', report.body);
});
});
// 开始监听
observer.observe();
复制代码
对比总结
| API | 监听目标 | 异步性 | 典型场景 | 浏览器支持 |
|---|---|---|---|---|
MutationObserver | DOM 结构/属性变化 | ✅ | 动态内容、防篡改 | 主流浏览器全支持 |
IntersectionObserver | 元素可见性 | ✅ | 懒加载、曝光统计 | 主流浏览器全支持 |
ResizeObserver | 元素尺寸变化 | ✅ | 响应式布局、图表自适应 | 主流浏览器全支持 |
PerformanceObserver | 性能指标 | ✅ | 性能监控、优化分析 | 主流浏览器全支持 |
ReportingObserver | 浏览器报告 | ✅ | 废弃 API 监控、CSP 日志 | Chrome 70+、Firefox 支持 |
使用注意事项
- 内存管理:及时调用
disconnect()或unobserve()避免内存泄漏。 - 性能优化:避免在回调中执行耗时操作,优先使用防抖/节流。
- 兼容性处理:旧版浏览器需引入 Polyfill(如
resize-observer-polyfill)。 - 阈值精细化:如
IntersectionObserver的threshold可设为数组[0, 0.25, 0.5, 1]实现多级触发。
通过合理使用 Observer API,可显著提升复杂 Web 应用的性能和用户体验。