DEV Community

Discussion on: Javascript DOM Manipulation to improve performance

Collapse
 
_developit profile image
Jason Miller 🦊⚛

FWIW DocumentFragment rarely provides much of a performance benefit these days. Also, in most cases imperative DOM construction is much faster than innerHTML and it's variants (insertAdjacentHTML etc), especially since the HTML parser's performance can be severely impacted by browser extensions like ad blockers. The only trick to remember is that when building DOM up imperatively, you should always build a detached tree first, then apped the fully constructed tree to the document.

Collapse
 
alephnaught2tog profile image
Max Cerrina

The only trick to remember is that when building DOM up imperatively, you should always build a detached tree first, then apped the fully constructed tree to the document.

Why? I'm assuming it's because a smaller tree traverses faster, yeah?

Collapse
 
_developit profile image
Jason Miller 🦊⚛

Mutating a disconnected tree is cheaper than a connected one because it has no chance of causing side effects like layout. So you build up the largest possible disconnected tree, then "commit" all those mutations by attaching its root.

Collapse
 
yhorobey profile image
yhorobey • Edited

Newdays DOM is smart enough to not launch reflow after each DOM change.
The trick is "do not ask DOM for values which are not available without reflow".

For example:
You have some container, div, you add to it a couple of other elements and after each addition you ask DOM "what is height of the parent div". Most likelly this will cause a reflow and this is very costly operation.

Collapse
 
Sloan, the sloth mascot
Comment deleted
Collapse
 
_developit profile image
Jason Miller 🦊⚛ • Edited

A detached tree (or disconnected tree) is a DOM tree that hasn't been added to the document yet. Mutating DOM nodes that are not currently appended to a document is extremely cheap.
Example:

Slow Version
Items are appended to the list, which is already "connected" because it has been inserted into document.body:

let list = document.createElement('ul');
document.body.appendChild(list);
for (let i = 0; i < 1000; i++) {
  let item = document.createElement('li');
  item.textContent = `Item ${i}`;
  list.append(item);
}
Enter fullscreen mode Exit fullscreen mode

Fast Version
All we have to change here is to move the document.body.appendChild(list) to the end.
Because items are appended to the list before the list is appended to document.body, building up each item and inserting it into the list is very cheap. Rendering can only happen after the very last line of code executes.

let list = document.createElement('ul');
for (let i = 0; i < 1000; i++) {
  let item = document.createElement('li');
  item.textContent = `Item ${i}`;
  list.append(item);
}
document.body.appendChild(list);  // we just moved this to the end
Enter fullscreen mode Exit fullscreen mode