Why is MutationObserver fired twice for childList but never for characterData?

I have a simple installation of MutationObserver as a test. HTML has a span whose text content is updated once per second (and a div for messages):

 <span class="tester"></span> <div id="msg"></div> 

MutationObserver is configured to view .tester and write text in the #msg div when it notices a change. Meanwhile, setInterval() works once / second to change the text in .tester :

 var target = document.querySelector('.tester'); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { console.log(mutation.type); $('#msg').append(mutation.type+"<br/>") setTimeout(function() { $('#msg').text(''); }, 500); }); }); var config = { attributes: true, childList: true, characterData: true }; observer.observe(target, config); setInterval(function() { $('#msg').text(''); $('.tester').text("update: "+Math.random()) }, 1000); 

I would expect this code to print once per second that characterData has changed. According to Mozilla's docs for MutationObserver , he talks about characterData: "Set to true if you need to track mutations for the target data." Instead, I don't see characterData mutations, but each time I see two childList mutations.

Why don't I see any characterData mutations and why do I see two childList mutations?

Here is a working example with CodePen .

+5
source share
1 answer

The reason is what Jeremy Banks said : when you use jQuery text() , it deletes all text nodes, and then adds new ones. This is not a change in character data, this is a change on childList : deleting the node there and replacing it with a new one.

To see a change in character data, you must modify the existing node nodeValue texts, and watch for subtree changes:

 var target = document.querySelector('.tester'); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { snippet.log(mutation.type); $('#msg').append(mutation.type+"<br/>") setTimeout(function() { $('#msg').text(''); }, 500); }); }); var config = { attributes: true, childList: true, characterData: true, subtree: true // <=== Change, added subtree }; observer.observe(target, config); var timer = setInterval(function() { $('#msg').text(''); // Change --VVVVV modifying the existing child node $('.tester')[0].firstChild.nodeValue = "updated" + Math.random(); }, 1000); // Stop after 10 seconds setTimeout(function() { clearInterval(timer); }, 10000); 
 <span class="tester">x</span><!-- Change, added a starting child node --> <div id="msg"></div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 --> <script src="//tjcrowder.imtqy.com/simple-snippets-console/snippet.js"></script> 

To your question about why there are two childList mutations, yes, I think you are right: they remove the child, and then add a new one. If we use the replaceChild method, we see only one mutation:

 var target = document.querySelector('.tester'); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { snippet.log(mutation.type); $('#msg').append(mutation.type+"<br/>") setTimeout(function() { $('#msg').text(''); }, 500); }); }); var config = { attributes: true, childList: true, characterData: true, subtree: true // <=== Change, added subtree }; observer.observe(target, config); var timer = setInterval(function() { $('#msg').text(''); // Change --VVVVV modifying the existing child node var text = document.createTextNode("updated" + Math.random()); var parent = $('.tester')[0]; parent.replaceChild(text, parent.firstChild); }, 1000); // Stop after 10 seconds setTimeout(function() { clearInterval(timer); }, 10000); 
 <span class="tester">x</span><!-- Change, added a starting child node --> <div id="msg"></div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 --> <script src="//tjcrowder.imtqy.com/simple-snippets-console/snippet.js"></script> 
+5
source

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


All Articles