Skip to content

前端5个Observer

5个Observer有哪些?

  • MutationObserver
  • IntersectionObserver
  • ResizeObserver
  • PerformanceObserver
  • ReportingObserver

MutationObserver

用途:提供了监视对 DOM 树所做更改的能力, 并捕捉这些变化。

md
const next = window.requestAnimationFrame ? requestAnimationFrame : setTimeout;
const ignoreDOMList = ["style", "script", "link"];

observer = new MutationObserver((mutationList) => {
  const entry = {
    children: [],
  };

  for (const mutation of mutationList) {
    //捕捉删除的节点
    if (mutation.removedNodes.length) {
      // ...
    }
    //捕捉添加的节点
    if (mutation.addedNodes.length ) {
      // ...
    }
  }
});
//监控对象为document对象,也可以修改为具体的DOM对象
observer.observe(document, {
  childList: true,
  subtree: true,
});

调用observe后开始监听DOM变化,如果要停止观察,需要调用observer.disconnect()方法。

IntersectionObserver

监听一种异步观察目标元素与其祖先元素或顶级文档视口(viewport)交叉状态的方法,然后在可视比例达到某个阈值的时候触发回调。

场景:图片懒加载实例

md
<img data-src="./imgs/1.jpg" alt="懒加载" />
<img data-src="./imgs/2.png" alt="懒加载" />
<img data-src="./imgs/3.jpg" alt="懒加载" />
<img data-src="./imgs/4.jpg" alt="懒加载" />
<img data-src="./imgs/5.jpg" alt="懒加载" />

javascript实现

md
document.addEventListener("DOMContentLoaded", () => {
  if ("IntersectionObserver" in window) {
    const imgs = document.getElementsByTagName("img");
    const imageObserve = new IntersectionObserver(
      (entries) => {
          entries.forEach((entry) => {
              if (entry.isIntersecting) {
                  console.log("进入可视区");
                  const img = entry.target;
                  img.src = img.dataset.src;
                  imageObserve.unobserve(img);
              }else {
                  console.log("未进入可视区");
              }
          });
      },
      {
        threshold: [0.25],
      },
    );
    [...imgs].forEach((img) => {
        // 开启监视每一个元素
        imageObserve.observe(img);
    });
  } else {
    alert("您的浏览器不支持IntersectionObserver!");
  }
});

ResizeObserver

resize事件只针对窗口(window)触发,其他元素的尺寸调整通知可以使用ResizeObserver来实现。

基础用法:

md
const resizeObserver = new ResizeObserver((entries) => {
    entries.forEach((entry) => {
        console.log(entry.target);
        console.log(entry.contentRect);
    });
});
resizeObserver.observe(document.querySelector('.observer'));

PerformanceObserver

PerformanceObserver 用于监听记录 performance 数据的行为,一旦记录了就会触发回调,

performance 使用 mark 方法记录某个时间点

md
performance.mark("mark-test-start");

实现方法

md
const observer = new PerformanceObserver((entryList) => {
  entryList.getEntries().forEach((entry) => {
    var logMark = "";
    var logMeasure = "";
    if (entry.entryType === "mark") {
      logMark = `${entry.name}的startTime是: ${entry.startTime}`;
      console.log(logMark);
    }
    if (entry.entryType === "measure") {
      console.log(
        (logMeasure = `${entry.name}的duration时间是: ${entry.duration}`),
      );
    }
  });
});
observer.observe({
  entryTypes: ["mark", "measure", "resource"],
});
performance.mark("mark-test-end");

创建 PerformanceObserver 对象,监听 mark(时间点)、measure(时间段)、resource(资源加载耗时)这三种记录时间的行为。也可以监测navigation(导航数据),first-input(fid指标)、layout-shift(cls指标),largest-contentful-paint(LCP指标)、longtask

ReportingObserver

监听过时的 api、浏览器的一些干预行为的报告。

md
//types也可以为crash
const options= {types: ['intervention', 'deprecation'], buffered: true}

const reportingObserver = new ReportingObserver((reports, observer) => {
    for (const report of reports) {
        console.log(report.body);//上报
    }
}, options);
reportingObserver.observe();

options 用来过滤上报的类型,buffered表示Observer实例创建前会生成report。

如果使用的sentry,可以参考ReportingObserver

友情提醒,用完Observer最后一定要disconnect,切记~切记~

陕ICP备15010740号