I have a function which goes through the direct child elements of a DOM node, and appends them to another freshly created Node, when they match a requirement. Then the function replaces the original DOM node with the one I created.
As appending the children to the new DOM node also removes them from the original DOM node, I wonder if I trigger a reflow on each removal, and if it will bring advantages if I wrap the function into requestAnimationFrame()
. Will this then trigger a reflow only once?
I ask this because MDN only talk about animations and not about adding/removing DOM nodes.
For reference, this is the function:
function fix_paragraphs(old){
cleanup_whitespace(old) // library function
let fixed = create('div') // library function
copy_attribs(old, fixed) // library function
let brs = []
let p = create('p')
while (old.hasChildNodes()) {
const child = old.firstChild
const childtype = child.nodeType
if (childtype === Node.ELEMENT_NODE && child.tagName === 'BR') {
brs.push(child)
old.removeChild(child)
}
else if (childtype === Node.ELEMENT_NODE && child.tagName === 'DIV') {
if (p.hasChildNodes()) {
fixed.appendChild(p)
}
p = create('p')
fixed.appendChild(child)
brs = []
}
else if ( (brs.length > 1) && (p.hasChildNodes()) ) {
fixed.appendChild(p)
p = create('p')
p.appendChild(child)
brs = []
}
else if (brs.length === 1) {
p.appendChild(brs[0])
p.appendChild(child)
brs = []
}
else {
p.appendChild(child)
brs = []
}
}
if (p.hasChildNodes()) {
fixed.appendChild(p)
}
replace_with(old, fixed) // library function
}
I checked the function in Dev Tools and figured out, by inspecting the rasterize paint entries, how to make it run twice as fast, by first popping the parent element from which I remove nodes (old
in the code). The updated code goes like this:
function fix_paragraphs(old){
let parent = old.parentNode
let next = old.nextSibling
old.remove() // pop it first
cleanup_whitespace(old)
let fixed = create('div')
copy_attribs(old, fixed)
let brs = []
let p = create('p')
while (old.hasChildNodes()) {
const child = old.firstChild
const childtype = child.nodeType
if (childtype === ELEM && child.tagName === 'BR') {
brs.push(child)
old.removeChild(child)
}
else if (childtype === ELEM && child.tagName === 'DIV') {
if (p.hasChildNodes()) {
fixed.appendChild(p)
}
fixed.appendChild(child)
p = create('p')
brs = []
}
else if ( (brs.length > 1) && (p.hasChildNodes()) ) {
fixed.appendChild(p)
p = create('p')
p.appendChild(child)
brs = []
}
else if (brs.length === 1) {
p.appendChild(brs[0])
p.appendChild(child)
brs = []
}
else {
p.appendChild(child)
brs = []
}
}
if (p.hasChildNodes()) {
fixed.appendChild(p)
}
parent.insertBefore(fixed, next) // now insert it again
}
Thanks for the tips, dantechguy and Kaiido.