# Tree Walker

**URL:** <https://forum.kirupa.com/t/tree-walker/651385>\
**Category:** Uncategorized\
**Created:** [April 3, 2022, 11:45am UTC](https://forum.kirupa.com/t/tree-walker/651385 "2022-04-03T11:45:48Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![steve.mills](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/steve.mills/32/14961_2.png) [@steve.mills](https://forum.kirupa.com/u/steve.mills)\
**Post date:** [April 3, 2022, 11:45am UTC](https://forum.kirupa.com/t/tree-walker/651385/1 "2022-04-03T11:45:48Z")

</div>

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.

```auto
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

```auto
        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…

```auto

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++;
                }
        }
    }

```

---

<div class="post-metadata">

**Author:** ![kirupa](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/kirupa/32/11616_2.png) [@kirupa](https://forum.kirupa.com/u/kirupa)\
**Post date:** [April 4, 2022, 3:43pm UTC](https://forum.kirupa.com/t/tree-walker/651385/2 "2022-04-04T15:43:39Z")

</div>

This is really cool. I don’t think I’ve used createTreeWalker ever outside of maybe you mentioning this a while ago 🙂

---

<div class="post-metadata">

**Author:** ![steve.mills](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/steve.mills/32/14961_2.png) [@steve.mills](https://forum.kirupa.com/u/steve.mills)\
**Post date:** [April 4, 2022, 10:24pm UTC](https://forum.kirupa.com/t/tree-walker/651385/3 "2022-04-04T22:24:57Z")

</div>

It looks it would be pretty handy for web scraping…

I’ve got a few large volume professional JS books that cover `ES6+` inside out and they don’t have much on it. It’s like the authors have never used in before either.

I had a use case where I wanted to query elements as well as text nodes and `XPath` looked like a horrible option…

Once I stumbled on it, I realized how powerful it is…

It’s pretty handy with `custom-elements` to query all `elementChildren.`  
It flattens the children and iterates 50% faster than` querySelectorAll(*)` which is good when you do that on a heap of `custom-elements`.

It’s also very handy for HTML tables. I just wish Safari would sort it out and implement customized built in elements so we could extend `<tr>` to `<table-row>`

---

<div class="post-metadata">

**Author:** ![steve.mills](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/steve.mills/32/14961_2.png) [@steve.mills](https://forum.kirupa.com/u/steve.mills)\
**Post date:** [April 17, 2022, 6:40am UTC](https://forum.kirupa.com/t/tree-walker/651385/4 "2022-04-17T06:40:57Z")

</div>

Just FYI:

- If your using a `treeWalker()` and you intend to replace/ remove nodes go with a `nodeIterator()` because it flattens the tree and will iterate where `treeWalker()` will stop if the branch is removed/ replaced.

- If you replace/ append nodes using a `nodeIterator()` and then intend to iterate over those you will need to set `node = iterator.referenceNode` (last node before replace/ append) and then `node = iterator.nextNode()`
