I just learned about DocumentFragment
, but I’m not entirely sure how to use it with what I have so far. I have around 9K-10K rows in my table and it takes about 4 seconds to load the entire table.
for (const user of totalsArray)
{
const truncatedUsername = truncateUsername(user);
const newRow = table.insertRow(table.rows.length);
const newCell0 = newRow.insertCell(USERNAME_IDX);
const newCell1 = newRow.insertCell(TOTAL_COMMENTS_IDX);
const newCell2 = newRow.insertCell(TOTAL_SCORE_IDX);
const newCell3 = newRow.insertCell(TOTAL_NEG_COMMENTS_IDX);
const userName = document.createTextNode(truncatedUsername);
const totalComments = document.createTextNode(user[TOTAL_COMMENTS_IDX]);
const totalScore = document.createTextNode(user[TOTAL_SCORE_IDX]);
const totalNegatives = document.createTextNode(user[TOTAL_NEG_COMMENTS_IDX]);
newCell0.appendChild(userName)
newCell1.appendChild(totalComments);
newCell2.appendChild(totalScore);
newCell3.appendChild(totalNegatives);
}
From what I understand, you make the new fragment with new DocumentFragment()
, then you append to it instead of the DOM, then when you are done with the main loop, you append the fragment to the DOM. But I am not seeing a way to do that with the way I am currently inserting cells into the row, and then appending a new text node to each cell. How does DocumentFragment
fit in here?
2
Answers
Document fragments are a great way to optimize performance while dealing with multiple DOM manipulations. Instead of appending each node individually to the table, you can use a document fragment to hold them temporarily before adding them to the DOM.
MDN Article
You won’t win much here.
Given that everything is done synchronously it’s basically just the same action as if you were using a
DocumentFragment
already.And actually, you rarely win much in using
DocumentFragment
objects rather than dealing with the DOM directly (sometimes you even lose by doing so). The perfs boost from it is basically a myth from a decade ago. The browser just has to do the same things anyway when you append the fragment*.In some engines you may win by letting the parser deal with it entirely, i.e. by passing it an HTML markup trough
.insertAdjacentHTML()
or even.innerHTML
. That should get the best built-in optimizations. Just beware you shouldn’t pass untrusted data in there as you’d be at risk of XSS attacks.But the best in such a case is to not render all the cells in one call.
Instead use either pagination, or a scroll-based lazy-rendering.
Ps: Here is a twitter thread from Jake Archibald about this very misconception with some benchmarks.
* The only notable difference would be if you had an
MutationObserver
looking at the parent node, triggering one heavy action per MutationRecord, since you’d get them all separated instead of a single one in the case of a fragment.