Script Valley
JavaScript: The Complete Language
DOM Manipulation and Browser APIsLesson 5.4

The Intersection Observer and Mutation Observer APIs

IntersectionObserver, threshold, rootMargin, lazy loading pattern, MutationObserver, observing DOM changes, childList subtree, disconnecting observers, performance vs event listeners

Observing Without Polling

Browser Observer APIs let you react to changes without polling loops or scroll event handlers that fire on every pixel. They are designed for efficiency — callbacks are batched and run outside the main thread where possible.

IntersectionObserver — Detect Element Visibility

const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      entry.target.classList.add("visible");
      observer.unobserve(entry.target); // stop watching after reveal
    }
  });
}, {
  threshold: 0.2,                   // 20% visible triggers callback
  rootMargin: "0px 0px -50px 0px"  // shrink effective viewport
});

document.querySelectorAll(".reveal").forEach(el => observer.observe(el));

MutationObserver — Watch DOM Changes

const mutObs = new MutationObserver((mutations) => {
  mutations.forEach(m => {
    m.addedNodes.forEach(node => console.log("Added:", node));
  });
});

mutObs.observe(document.querySelector("#feed"), {
  childList: true, // watch direct children
  subtree: true    // include all descendants
});

mutObs.disconnect(); // always clean up when done

Performance and Cleanup

IntersectionObserver is far more efficient than a scroll listener — it runs asynchronously and is batched by the browser. Always call unobserve or disconnect when finished observing. Failing to do so creates memory leaks because the observer holds a reference to every observed element, keeping them alive in memory.

Up next

Timers, requestAnimationFrame, and browser rendering performance

Sign in to track progress