Created
May 8, 2020 20:03
-
-
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/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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