Observer APIs are handy in detecting change and can be used to create responsive applications.
There are four different types of observers that observe different things — from the DOM to browser performance.
MutationObserver
MutationObserver observes the DOM tree, listening for the changes made to the DOM.
// Select the node that will be observed for mutations const targetNode = document.getElementById('element'); // Options for the observer (which mutations to observe) const config = { attributes: true, childList: true, subtree: true, }; // Create an observer instance linked to a callback to execute when mutations are observed const observer = new MutationObserver((mutations, observer) => { mutations.forEach(mutation => { if (mutation.type === 'childList') { console.log('A child node has been added or removed.'); } else if (mutation.type === 'attributes') { console.log(`The ${mutation.attributeName} attribute was modified.`); } }); }); // Start observing the target node for configured mutations observer.observe(targetNode, config); // Later, you can stop observing observer.disconnect();
We will be notified when an element’s attributes, text, or contents changed and also monitors the child nodes whether it has been added or removed.
This is particularly useful for resizing elements in the DOM as well as resetting DOM values.
IntersectionObserver
IntersectionObserver observes a DOM element’s visibility, listening for changes in its positions.
// Select the node that will be observed for mutations const targetNode = document.getElementById('element'); // Options for the observer const config = { rootMargin: '-100% 0px 0px 0px', }; // Create an observer instance linked to a callback to execute when entries are observed const intersectionObserver = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { console.log('Observing.'); // Later, you can stop observing observer.unobserve(entry.target); } }); }); // Start observing intersectionObserver.observe(targetNode, config);
This is very useful in lazy loading and animating content based on the target element’s visibility and positions.
ResizeObserver
ResizeObserver observes elements’ content or border-box, listening for changes in the element and its children.
// Select the node that will be observed for mutations const targetNode = document.getElementById('element'); const resizeObserver = new ResizeObserver((entries, observer) => { entries.forEach(entry => { console.log(`Element size: ${entry.width}px x ${entry.height}px`); console.log(`Element padding: ${entry.top}px ; ${entry.left}px`); // Later, you can stop observing observer.unobserve(entry.target); }); }); // Start observing resizeObserver.observe(targetNode);
This observer is relevant when creating dynamic content that wraps based on input or triggers.
PerformanceObserver
PerformanceObserver observes performance measurement events, listening for new performance entries.
// Options for the observer const config = { entryTypes: ['resource', 'mark', 'measure'], }; const observer = new PerformanceObserver(list => { list.getEntries().forEach(entry => { // Display each reported measurement on console console.log( `Name: ${entry.name}`, `Type: ${entry.entryType}`, `Start: ${entry.startTime}`, `Duration: ${entry.duration}` ); }); }); // Start observing observer.observe(config); performance.mark('registered-observer');
This is useful for receiving performance notifications to be ran during idle time without competing with critical rendering work.
Conclusion
The observer APIs unlock the web’s hidden superpowers to create truly responsive experiences, from lazy-loading critical content to non-intrusive performance monitoring.