A faster way to replace text in all dom elements?

I am trying to replace all text between tags, and I want to find out the fastest way to do this.

An example would be an attempt to replace all text with an arbitrary string helloWorld, so that this:

<div>
    <div>
        RandomText1
        <div>
            RandomText2
        </div>
    </div>
</div>

Becomes as follows:

<div>
    <div>
        helloWorld
        <div>
            helloWorld
        </div>
    </div>
</div>

My current approach:

  • Do a depth search (DFS) in the DOM
  • For each element, analyze and determine which part is the text and which part is the element.
  • For the part that replaces the text.

This would be very slow for me, especially trying to do this for a large document and repeat this process many times. Is there a faster way?

+4
source share
5

, childNodes

var newText = 'hello world';
function replaceTextNodes(node) {
  node.childNodes.forEach(function(el) {
    if (el.nodeType === 3) {  // If this is a text node, replace the text
      if (el.nodeValue.trim() !== "") { // Ignore this node it it an empty text node
        el.nodeValue = newText;
      }
    } else { // Else recurse on this node
      replaceTextNodes(el);
    }
  });
}

var onClick = replaceTextNodes.bind(null, document.querySelector('#container'));
document.querySelector('#replace').addEventListener('click', onClick);
<div id='container'>
  <div>
    RandomText1
    <div>
      RandomText2
      <ul>
        <li>RandomText3</li>
      </ul>
    </div>
  </div>
</div>
<button id="replace">Replace</button>
Hide result
+3

nodeIterator . , , . : , 6 . Snippet.

SNIPPET

/* Create a custom filter which will...
||...the 3rd parameter of createNodeIterator method...
*/

function textFilter(node) {
  // if .nodeType is 3 (3 is text, 1 is element)
  if (node.nodeType === 3) {
    // Set .nodeValue to 'hellowWorld'
    node.nodeValue = 'helloWorld';
    // Return NodeFilter object to accept node
    return NodeFilter.FILTER_ACCEPT;
  }
  // Otherwise ignore node
  return NodeFilter.FILTER_SKIP;
}

function findText() {
  // Reference the rootNode
  var content = document.querySelector('body');

  /* Create nodeIterator passing
  || content or rootNode
  || NodeFilter object or WhatToShow property
  || Custom filter function
  */
  var iterator = document.createNodeIterator(content, NodeFilter.SHOW_TEXT, textFilter);
  // Advance to the next sibling or descend to node children nodes 
  var node = iterator.nextNode();
  // While there is a node...
  while (node) {
    // ...Go on to it...rinse, lather, and repeat
    node = iterator.nextNode();
  }

}

findText();
.mark {
  color: red;
}
<div>
  <div>
    RandomText1
    <div>
      RandomText2
    </div>
  </div>
</div>
<div>
  <div>
    <div>
      <div>
        <div>
          <div class='mark'>
            6 Deep!
          </div>
        </div>
      </div>
    </div>
  </div>
  <div>
    RandomText1
    <div>
      RandomText2
    </div>
  </div>
</div>
<div>
  <div>
    RandomText1
    <div>
      RandomText2
    </div>
  </div>
</div>
<div>
  <div>
    RandomText1
    <div>
      RandomText2
    </div>
  </div>
</div>
<div>
  <div>
    RandomText1
    <div>
      RandomText2
    </div>
  </div>
</div>
Hide result
+1

TreeWalker DOM.
TreeWalker Document.createTreeWalker().

function replaceAllText(newText) {
    var walker = document.createTreeWalker(
        document.body,  // root node
        NodeFilter.SHOW_TEXT,  // filtering only text nodes
        null,
        false
    );
    
    while (walker.nextNode()) {
        if (walker.currentNode.nodeValue.trim())  // if it not empty(whitespaced) node
          walker.currentNode.nodeValue = newText;
    }
}

replaceAllText("helloWorld");
<div>
    <div>
        RandomText1
        <div>
            RandomText2
        </div>
    </div>
</div>
Hide result

https://developer.mozilla.org/en-US/docs/Web/API/Document/createTreeWalker

+1
source

The browser DOM search is very fast, and it is also optimized. Therefore, I would suggest adding some common class to the DOM elements that need to be changed, and then manipulate them using this class identifier.

Besides,

FYI document.getElementById()works in DFS and is quite efficient.

0
source

Scroll through your HTML code than find nodeValue like this:

document.querySelectorAll('div').forEach(function(o,i){
    console.log(o.firstChild && o.firstChild.nodeValue);
})

https://jsfiddle.net/q7ewbswx/

0
source

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


All Articles