rsk82
rsk82

Reputation: 29397

what is the most fast, safe and correct method for looping through whole DOM in pure JS?

By safe I mean the fact that NodeList created by document.getElementsById('*'); is a live object. Some elements are added or removed dynamically as JS engine loops through it.

The thing I intend to do is loop over a whole DOM (this would be in a greasemonkey script, so not for normal web use, but I think it also applies there), check if a node CSS match some rules and according to that change the CSS.

This process takes some time and since the website has multiple scripts (changing images/news stories etc.) running on it, constantly adding and removing DOM nodes sooner or later there will be a case when a node will disappear right when it is processed.

And by fast I mean is it better to do it recursively:

function traverseDOM(node,f) {
  if (node.nodeType !== 1) return;
  f.apply(node);
  for (var i = 0; i < node.childNodes.length; i++) {
    traverseDOM(node.childNodes[i],f);
  }
}

(but this will waste time on checking nodeType) or by for loop:

nodes = document.getElementsByTagName('*');
for (var i=0; i<nodes.length; i++) {
  //do my stuff
}

(but this would have issues at the end where it will encounter fluctuating tip of NodeList)

Upvotes: 0

Views: 194

Answers (3)

istos
istos

Reputation: 2662

Here is an example, feel free to give it a try. Tested it on about 170 nodes and it wasn't too slow, but it wasn't necessarily fast either:

function walk (node, func) {
    func(node);
    node = node.childNodes[0];

    while (node) {
        walk(node, func);
        node = node.nextSibling;
    }
}

var doc = document; //save a reference to the document (might be a tiny bit faster... not sure)
var bd = doc.body; //start to walk the DOM from the body
var o = doc.getElementById('some_div'); //some div to output to
var arr = []; //array to collect all nodes

walk(bd, function(n){
    if (n.nodeType === 1) {
        n.style.border = "2px solid red"; //change the border color for each node that was found
        o.innerHTML += "<pre>" + n.nodeName + "</pre>"; //output each node's name to a div
        arr.push(n); //add each node to the array
    }
});

console.log(arr.length); //log the total number of nodes affected

Upvotes: 1

Wolfgang Kuehn
Wolfgang Kuehn

Reputation: 12936

There is a w3c Element Traversal Specification, see example at http://www.w3.org/TR/ElementTraversal/#example-3.2

Upvotes: 0

Kosta
Kosta

Reputation: 832

JavaScript is single-threaded. Only one function can run at a time. While you iterate over the DOM, it should be impossible to be modified.

Upvotes: 0

Related Questions