javascriptinnertextdom-node

Where are these DOM nodes coming from when only changing innerText?


I created a simple loop using seInterval. Every time it calls the timeout function it sets the innerText property of an h1 element.

when I monitor the performance in chrome dev tools I can see that the DOM node count increases every time the timeout function is called, but more specifically when the innerText is assigned.

I'm wondering if changing the innerText property always creates new DOM nodes that are later cleaned up or if I am just not understanding something about innerText or how the DOM works.

enter image description here

Edit: I should mention that once the node count reaches about 1500 it drops back down to the starting count. I assume this is the garbage collector working.

(I just noticed that this doesn't happen when running the code snippet below, but it does when opening the file in the browser.)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Test</title>
</head>
<body>
<h1 class="title">
    HELLO
</h1>
<script>
  const title = document.querySelector('.title');
  title.innerText = 'HELLO';

  function onTimeout() {
    title.innerText = title.innerText === "HELLO" ? "BYE" : "HELLO";
  }
  setInterval(onTimeout, 500);
</script>
</body>
</html>


Solution

  • The only nodes that contains "raw" text are those implementing CharacterData interface, thus only Text, Comment and CDATASection nodes. Regular elements will use at least one of the mentioned nodes for textual content. Thus, no matter will use you innerText or textContent, there always will be inserted a new Text node. To circumvent this you may change the textContent of Text node that was previously inserted, like this:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Test</title>
    </head>
    <body>
    <h1 class="title">
        HELLO
    </h1>
    <script>
      const title = document.querySelector('.title');
      title.textContent = 'HELLO';
    
      function onTimeout() {
        title.firstChild.textContent = title.textContent === "HELLO" ? "BYE" : "HELLO";
      }
      setInterval(onTimeout, 500);
    </script>
    </body>
    </html>