Some recursive code is part of a particularly slow path of a project. Out of curiosity I was playing around with reimplementing the code using stack context iteration instead of recursion. Below are snippets reduced to just the iteration patterns of tree elements using a DOM structure for simplicity.
I was surprised when benchmarking the code that the recursive variant was faster than iterative approaches. Is there a flaw in my implementations (they each iterate the same number of elements to the same depth)? The snippets aren't strictly equivalent in the order they touch the elements though I doubt that effects the performance.
Recursive depth first approach
function iterate(current, depth) {
var children = current.childNodes;
for (var i = 0, len = children.length; i < len; i++) {
iterate(children[i], depth + 1);
}
}
iterate(parentElement, 0);
Iterative breadth first forwards
var stack = [{
depth: 0,
element: treeHeadNode
}];
var stackItem = 0;
var current;
var children, i, len;
var depth;
while (current = stack[stackItem++]) {
//get the arguments
depth = current.depth;
current = current.element;
children = current.childNodes;
for (i = 0, len = children.length; i < len; i++) {
stack.push({ //pass args via object or array
element: children[i],
depth: depth + 1
});
}
}
Iterative breadth first backwards approach
var stack = [{
depth: 0,
element: treeHeadNode
}];
var current;
var children, i, len;
var depth;
while (current = stack.pop()) {
//get the arguments
depth = current.depth;
current = current.element;
children = current.childNodes;
for (i = 0, len = children.length; i < len; i++) {
stack.push({ //pass args via object or array
element: children[i],
depth: depth + 1
});
}
}
I was expecting the second snippet to be fastest in JS (no array popping), is there opportunity for further optimization to improve the performance of the iterative approach? I believe part of the slowness is creating the arguments in an object (i.e. {depth: depth+1,element: someElement}
). The recursive snippet is more intuitive and explicit and may benefit from tail recursion in ES6 interpretors.
Repeating myself, is there a more performant way to iterate tree
data structures in JavaScript than recursively?
null
which simply changes the property's value thandelete
it which removes it from the object entirely, altering its shape. The object the property references is garbage collected either way, so there's no memory penalty. \$\endgroup\$depth
for? I see no use of it, besides adding up while it runs through the tree. \$\endgroup\$