// language=HTML
const html = `
<!-- article out start -->
<article>
<!-- article in start -->
<h1>Lorem ipsum</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Cumque, nostrum.</p>
<!-- article in end -->
</article>
<!-- article out end -->
<!-- article out start -->
<article>
<!-- article in start -->
<h1>Lorem ipsum</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Cumque, nostrum.</p>
<!-- article in end -->
</article>
<!-- article out end -->
<!-- article out start -->
<article>
<!-- article in start -->
<h1>Lorem ipsum</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Cumque, nostrum.</p>
<!-- article in end -->
</article>
<!-- article out end -->
`;
const template = document.createElement('template');
template.innerHTML = html;
window.testTemplate = template;
const elements = [];
function traverse(node) {
if (!node) return;
if (node.nodeType === Node.ELEMENT_NODE) {
elements.push(node);
}
traverse(node.nextElementSibling);
traverse(node.firstElementChild);
}
traverse(testTemplate.content.firstElementChild);
if (elements.length !== 9) throw new Error(`Expected 9 elements, got ${elements.length}`);
const nodeIterator = document.createNodeIterator(
testTemplate.content,
NodeFilter.SHOW_ALL,
{
acceptNode(node) {
if (node.nodeType === Node.ELEMENT_NODE) {
return NodeFilter.FILTER_ACCEPT;
}
return NodeFilter.FILTER_REJECT;
}
}
);
const elements = [];
while (nodeIterator.nextNode()) {
elements.push(nodeIterator.currentNode);
}
if (elements.length !== 9) throw new Error(`Expected 9 elements, got ${elements.length}`);
const nodeIterator = document.createNodeIterator(
testTemplate.content,
NodeFilter.SHOW_ELEMENT
);
const elements = [];
while (nodeIterator.nextNode()) {
elements.push(nodeIterator.currentNode);
}
if (elements.length !== 9) throw new Error(`Expected 9 elements, got ${elements.length}`);
const treeWalker = document.createTreeWalker(
testTemplate.content,
NodeFilter.SHOW_ALL,
{
acceptNode(node) {
if (node.nodeType === Node.ELEMENT_NODE) {
return NodeFilter.FILTER_ACCEPT;
}
return NodeFilter.FILTER_REJECT;
}
}
);
const elements = [];
while (treeWalker.nextNode()) {
elements.push(treeWalker.currentNode);
}
if (elements.length !== 9) throw new Error(`Expected 9 elements, got ${elements.length}`);
const treeWalker = document.createTreeWalker(
testTemplate.content,
NodeFilter.SHOW_ELEMENT
);
const elements = [];
while (treeWalker.nextNode()) {
elements.push(treeWalker.currentNode);
}
if (elements.length !== 9) throw new Error(`Expected 9 elements, got ${elements.length}`);
--enable-precise-memory-info
flag.
Test case name | Result |
---|---|
Traverse function | |
NodeIterator with filter function | |
NodeIterator with filter param | |
TreeWalker with filter function | |
TreeWalker with filter param |
Test name | Executions per second |
---|---|
Traverse function | 4022718.0 Ops/sec |
NodeIterator with filter function | 103098.7 Ops/sec |
NodeIterator with filter param | 1703766.1 Ops/sec |
TreeWalker with filter function | 95947.6 Ops/sec |
TreeWalker with filter param | 1571171.5 Ops/sec |
Let's break down what's being tested in this benchmark.
Benchmark Goal: The goal of this benchmark is to compare the speed of three different ways to traverse a DOM tree (a hierarchical structure used by web browsers to represent and manipulate HTML documents).
Test Cases:
testTemplate.content.firstElementChild
). The function checks if each node is an ELEMENT_NODE
and pushes it to an array.ELEMENT_NODE
, ensuring only element nodes are visited. The iterator is used to push node references to an array.NodeFilter.SHOW_ELEMENT
) that accepts only ELEMENT_NODE
nodes by default.ELEMENT_NODE
nodes are visited.Comparison:
Benchmark Results: The latest benchmark results show that:
In general, these results suggest that the tree walker approach is a good choice when traversing DOM trees in performance-critical code paths.