For
loops that interact with and manipulate the DOM may look simple, but can be a huge performance buster, depending on what is going on. But let’s look at best practices anyway and write better code.
Original Unoptimized Code
Here is our initial code. This for
loop loops through a bunch of child elements and removes a class, which can trigger a style recalculation. There may be other code in the loop that can cause layout thrashing and style recalculation for each iteration of the loop!
const childElems = document.querySelectorAll('.child-elem');
for(let l = 0; l < childElems.length; l++) {
childElems[l].classList.remove("bad-class");
// do other potentially expensive DOM work...
}
Code language: JavaScript (javascript)
Let’s look at two solutions to git ‘er optimized.
1. removeChild & appendChild
If we use removeChild, then we can do our work on the elements that are removed or detached from the DOM, and then add them back later with appendChild.
Note that a reference to the removed element must be kept for us to be able to modify and re-insert it later.
const someElem = document.querySelector('.some-elem');
const parentElem = someElem.parentElement;
const removedContainer = parentElem.removeChild(someElem);
const removedItems = Array.from(removedContainer.children);
for(let l = 0; l < removedItems.length; l++) {
removedItems[l].classList.remove("red");
// Do other potentially expensive DOM work...
}
// Insert the removed element back into the DOM
parentElem.appendChild(removedContainer);
Code language: JavaScript (javascript)
2. cloneNode & replaceChild
If we use cloneNode and replaceChild, then we can achieve a similar result. Be warned that cloneNode does not copy any event listeners that may have been added by addEventListener to (I believe any) elements within the clonedNode.
const someElem = document.querySelector('.some-elem');
const clonedElem = someElem.cloneNode(true);
const clonedItems = Array.from(clonedElem.children);
for(let l = 0; l < clonedItems.length; l++) {
clonedItems[l].classList.remove("bad-class");
// Do other potentially expensive DOM work...
}
// Insert the removed element back into the DOM with replaceChild(new, old)
someElem.parentElement.replaceChild(clonedElem,someElem);
Code language: JavaScript (javascript)