Take two
I’ve been digging into document.createTreeWalker()
lately…
It’s a little bit syntax heavy but pretty powerfull.
The pro’s are:
- 2X speed on
document.querySelectorAll(*)
- Within 5% ± of querySelectorAll(elements)
- Way more capable with filter options
- Can query any node type inc text, comment, attr ect
IF… the treeWalker is used with a loop and not a callback
The basic syntax is:
let walker = document.createTreeWalker( element, NodeFilter.SHOW_ELEMENT, filterCallback , false);
This will run the walker looking for node type element
with a callBack filter function
.
The performance on this is 10X slower than querySelectorAll()
due to the callback function being invoked every node…
However if you put your filter in the loop
the speed is the same but you have more options and you can also walk over Child/ Sibling and Parent nodes
before continuing the loop…
There’s two main ways to do this (make walker filter param null):
with a while loop
(somewhat costly if called repeatedly) e.g.
let iter = 0;
let node = walker.nextNode();
while(node){
if(node.tagName === 'DIV'){ node.className = "classy";
node = walker.nextNode(); iter ++
}
Or with a for loop (more performant if less than 1000) e.g
for(let node = walker.nextNode(), i = 0; // assign loop vars
node; // evaluate if (node == null) break
node = walker.nextNode() // iterate loop onto the next node
){
if(node.tagName === 'DIV'){ node.className == 'classy"; i++;
}
}
This is how I’ve been using it but the options are pretty much limitless…
const diffNodes = function(element, objects, props){
let walker = document.createTreeWalker(element, NodeFilter.SHOW_ELEMENT, null, false);
for(let node = walker.nextNode(), i = 0;
node;
node = walker.nextNode()){
if(node.tagName === objects[i].tag){
if(objects[i].text) node.insertBefore(document.createTextNode(objects[i].text), node.childNodes[0])
for(let prop in props ){
node[prop] = objects[prop]
}
i++;
}
}
}