Skip to content

Instantly share code, notes, and snippets.

@cferdinandi
Created May 8, 2020 20:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cferdinandi/8d1d77486c0d6e7cfccbb4425b0e0543 to your computer and use it in GitHub Desktop.
Save cferdinandi/8d1d77486c0d6e7cfccbb4425b0e0543 to your computer and use it in GitHub Desktop.
Performance testing the DOM Tree Walker API vs. a hand-rolled mapDOM() function. More on performance testing JS here: https://gomakethings.com/how-to-test-vanilla-js-performance/
var mapDOM = function (elem) {
return {
NODE: elem,
ATTRIBUTES: elem.attributes,
PARENT: elem.parentNode,
CHILDREN: Array.prototype.map.call(elem.childNodes, function (child) {
return mapDOM(child);
})
};
};
var createTreeWalker = function () {
const TREEWALKER = document.createTreeWalker(document, NodeFilter.SHOW_ALL, {
acceptNode: function (node) {
if (node.nodeType === 1 || (node.nodeType === 3 && node.nodeValue.trim().length !== 0)) {
return NodeFilter.FILTER_ACCEPT;
}
return NodeFilter.FILTER_REJECT;
},
});
const DOMTREE = [];
/**
* Init the lastNode/DOMTREE with the TREEWALKER.currentNode (document)
*/
let lastNode = {
NODE: TREEWALKER.currentNode,
CHILDREN: [],
/**
* The TREEWALKER begins from document, so it shouldn't require the "ATTRIBUTES", "PARENT" or "SIBLINGS" properties.
*/
// ATTRIBUTES: TREEWALKER.currentNode.attributes,
// PARENT: {},
// SIBLINGS: [],
};
DOMTREE.push(lastNode);
/**
* Helper function for setting the siblings of an element.
* Approach is to loop through the parents child, for each child take the list of the parents children, and then filter out the child itself.
* Then we're left with a sibling-list for each child.
* @param {Node} node
*/
while (true) {
/**
* Lets walk down the tree with our little TREEWALKER :)
*/
let nextNode = TREEWALKER.nextNode();
/**
* Exit ouf of the while-loop when all of the nodes have been looped through.
*/
if (!nextNode) break;
const currentNode = {
NODE: nextNode,
ATTRIBUTES: nextNode.attributes,
PARENT: {},
CHILDREN: []
};
/**
* If the previous node (lastNode) is the parent of this one, then assign it as currentNodes parent and add currentNode to the lastNodes CHILDREN-list.
*/
if (currentNode.NODE.parentNode === lastNode.NODE) {
currentNode.PARENT = lastNode;
lastNode.CHILDREN.push(currentNode);
} else if (currentNode.NODE.parentNode === lastNode.NODE.parentNode) {
/**
* If the lastNode has same parent as currentNode then it's a sibling.
* Give currentNode the same parent and add currentNode to its parent CHILDREN-list
*/
currentNode.PARENT = lastNode.PARENT;
currentNode.PARENT.CHILDREN.push(currentNode);
} else {
/**
* If the lastNode was not a sibling or a parent of currentNode, then we know that the lastNode was the last sibling in its group (because the last check was the sibling-check).
* Begin looping through the lastNodes parents children to find the sibling of the currentNode.
*/
let temporaryNode = lastNode;
while (true) {
/**
* For each iteration, set the siblings of the temporaryNode (on first iteration: lastNode | else: parent of the nodes we loop through)
*/
/**
* The lastNode is a child in any DOM-group (don't know which yet).
* We search up the DOM-tree until we find the parent that equals currentNodes sibling.
* Then we add the temporaryNodes parent to the SIBLINGS list of currentNode and vise versa.
* Lastly we set the parent of currentNode and also add the currentNode to its parent CHILDREN-list.
*/
if (temporaryNode.PARENT.NODE === currentNode.NODE.previousElementSibling) {
currentNode.PARENT = temporaryNode.PARENT.PARENT;
currentNode.PARENT.CHILDREN.push(currentNode);
break;
} else {
/**
* Go up one step and set the siblings of the the parent.
*/
temporaryNode = temporaryNode.PARENT;
}
}
}
/**
* Set the currentNode to the lastNode and prepare for another loop!
*/
lastNode = currentNode;
/**
* Push to DOMTREE if a full list with each single element is wanted
*/
// DOMTREE.push(currentNode);
}
return TREEWALKER;
};
console.time('mapDOM');
for (var i = 0; i < 10000; i++) {
mapDOM(document.body);
}
console.timeEnd('mapDOM');
console.time('treeWalker');
for (var i = 0; i < 10000; i++) {
createTreeWalker();
}
console.timeEnd('treeWalker');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment