⬆️ ⬇️

How JS Works: Tracking DOM Changes with MutationObserver

Today, in the translation of the tenth material from a series on the features of the JavaScript mechanisms, we will talk about how to track changes in the DOM using the MutationObserver API.



Client parts of web applications are becoming more and more complex and require more and more system resources. This happens for various reasons, in particular due to the fact that such applications need advanced interfaces, thanks to which their capabilities are revealed, and because they have to perform complex calculations on the client side.





')

All this leads to the complication of the task of monitoring the state of application interfaces during their life cycle. This task becomes even bigger if we are talking about developing something like a framework or even a regular library, when, for example, you need to react to what is happening with the page and perform some actions dependent on the DOM.



[We advise you to read] Other 19 parts of the cycle
Part 1: Overview of the engine, execution time mechanisms, call stack

Part 2: About the V8 internals and code optimization

Part 3: Memory management, four types of memory leaks and dealing with them

Part 4: Event loop, asynchrony, and five ways to improve code with async / await

Part 5: WebSocket and HTTP / 2 + SSE. What to choose?

Part 6: Features and Scope of WebAssembly

Part 7: Web Workers and Five Use Cases

Part 8: Service Workers

Part 9: Web push notifications

Part 10: Tracking DOM Changes with MutationObserver

Part 11: The engines of rendering web pages and tips to optimize their performance

Part 12: Browser networking subsystem, optimizing its performance and security

Part 12: Browser networking subsystem, optimizing its performance and security

Part 13: Animation with CSS and JavaScript

Part 14: How JS works: abstract syntax trees, parsing and its optimization

Part 15: How JS Works: Classes and Inheritance, Babil and TypeScript Transformation

Part 16: How JS Works: Storage Systems

Part 17: How JS Works: Shadow DOM Technology and Web Components

Part 18: How JS: WebRTC and P2P Communication Mechanisms Work

Part 19: How JS Works: Custom Elements


Overview



MutationObserver is a Web API provided by modern browsers for detecting changes in the DOM. Using this API, you can monitor the addition or removal of DOM nodes, changes in the attributes of elements, or, for example, changes in the text of text nodes. Why do you need it?



There are many situations in which the API MutationObserver can be very useful. For example:







Browser-based text editor



The above are just a few situations in which MutationObserver features may be useful. In fact, they are much more.



How to use MutationObserver



Using MutationObserver in web applications is quite simple. You need to create an instance of MutationObserver , passing in the appropriate constructor a function that will be called every time changes occur in the DOM. The first argument of the function is a collection of all mutations that occurred in the form of a single package. For each mutation, information is provided about its type and about the changes it represents.



 var mutationObserver = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) {   console.log(mutation); }); }); 


The created object has three methods:





Here's how to enable change monitoring:



 //       HTML-  mutationObserver.observe(document.documentElement, { attributes: true, characterData: true, childList: true, subtree: true, attributeOldValue: true, characterDataOldValue: true }); 


Now suppose that the DOM has the simplest div element:



 <div id="sample-div" class="test"> Simple div </div> 


Using jQuery, you can remove the class attribute from this element:



 $("#sample-div").removeAttr("class"); 


Due to the fact that we started monitoring the changes, having previously called mutationObserver.observe(...) , and the fact that the function that reacts to the arrival of a new package of changes, displays the data in the console, we will see in the console the contents of the corresponding MutationRecord object:





MutationRecord object



Here you can see the mutations caused by the deletion of the class attribute.



And finally, in order to stop monitoring the DOM after the work is completed, you can do the following:



 //     mutationObserver.disconnect(); 


MutationObserver support in various browsers



The MutationObserver API has broad browser support:





MutationObserver support



Alternatives to MutationObserver



It is worth noting that the DOM change monitoring mechanism offered by MutationObserver was not always available to developers. What did they use before the appearance of MutationObserver ? Here are a few options:





â–ŤInquiry



The easiest and easiest way to track changes in a DOM is polling. Using the setInterval method, you can schedule periodic execution of a function that checks the DOM for changes. Naturally, the use of this method significantly reduces the performance of web applications.



â–ŤMutationEvents



API MutationEvents was introduced in 2000. Despite the fact that this API allows solving the tasks assigned to it, mutation events are triggered after each DOM change, which, again, leads to performance problems. Now the API MutationEvents is deprecated and soon modern browsers will no longer support it.





MutationEvents support



â–ŤCSS-animation



In fact, the alternative to MutationObserver in the form of CSS animations may seem somewhat strange. And here is the animation? In general, the idea here is to create an animation that will be called after the element is added to the DOM. At the time the animation starts, the animationstart event will be triggered. If you assign a handler for this event, you can find out the exact time of adding a new element to the DOM. At the same time, the execution time of the animation should be so small that it is almost invisible to the user.



To use this method, you first need a parent element, the addition to which new nodes we want to observe:



 <div id="container-element"></div> 


To organize the monitoring of adding nodes to it, you need to set up a sequence of key frames for CSS animation that will start when you add a node:



 @keyframes nodeInserted { from { opacity: 0.99; } to { opacity: 1; } } 


After creating keyframes, the animation should be applied to the elements that you want to monitor. Pay attention to the duration of the animation. It is very small, so the animation is almost invisible.



 #container-element * { animation-duration: 0.001s; animation-name: nodeInserted; } 


Here we add animation to all descendant nodes of the container-element . When the animation ends, the corresponding event is raised.



Now you need a JS function that will play the role of an event handler. Inside the function, first of all, you need to check the event.animationName in order to make sure that this is the animation that interests us.



 var insertionListener = function(event) { //   ,     ,    if (event.animationName === "nodeInserted") {   console.log("Node has been inserted: " + event.target); } } 


Now add an event handler to the parent element. This is done differently in different browsers:



 document.addEventListener("animationstart", insertionListener, false); // standard + firefox document.addEventListener("MSAnimationStart", insertionListener, false); // IE document.addEventListener("webkitAnimationStart", insertionListener, false); // Chrome + Safari 


This is the situation with the support of CSS-animation in various browsers.





Support for CSS animations in various browsers



Results



We looked at the MutationObserver API and alternative ways to monitor DOM changes. It should be noted that MutationObserver has many advantages over these alternatives. In general, we can say that this API is able to report any changes that may occur in the DOM, that it is well optimized, giving information about changes collected in packages. In addition, the MutationObserver API is supported by all major modern browsers, and there are polyfills for it based on MutationEvents .



The author of the material notes that MutationObserver is central to the SessionStack library, which aims to organize the collection of data about what happens to web pages.



Previous parts of a series of articles:



Part 1: How JS Works: Overview of the Engine, Runtime Mechanisms, Call Stack

Part 2: How JS Works: About V8 Inside and Code Optimization

Part 3: How JS works: memory management, four types of memory leaks and how to deal with them

Part 4: How JS works: event loop, asynchrony, and five ways to improve code with async / await

Part 5: How JS: WebSocket and HTTP / 2 + SSE work. What to choose?

Part 6: How JS Works: Features and Scope of WebAssembly

Part 7: How JS Works: Web Workers and Five Use Cases

Part 8: How JS Works: Service Workers

Part 9: How JS Works: Web Push Notifications



Dear readers! Do you use MutationObserver in your projects?



Source: https://habr.com/ru/post/351256/



All Articles