Rendering Example
The slowest way to render a list is the obvious one: append each row to the page inside a loop. Every append can force the browser to recalculate layout, so a thousand rows can mean a thousand reflows. This example shows the fix, building all the rows in an off-screen fragment and inserting them in a single operation, with the timing to prove the difference.
For the mechanics underneath, see DOM rendering performance and the browser rendering pipeline.
What you'll learn
What this example builds
The example renders a list of one thousand items two ways, the naive loop and a fragment-based version, and logs how long each takes.
The behaviour you will see
The naive version appends each item directly to the container and is noticeably slower, because each append can trigger layout work. The fragment version assembles everything off-screen and inserts it once, so the browser lays out the list a single time. The console timings make the gap concrete.
The slow approach
This is the version most people write first, and it is the one to avoid for large lists.
Appending in a loop
var list = document.getElementById("list");
for (var i = 0; i < 1000; i++) {
var li = document.createElement("li");
li.textContent = "Item " + i;
list.appendChild(li); // touches the live DOM every iteration
}
The fast approach
Building the rows away from the page first means the browser only does layout once.
Using a document fragment
var frag = document.createDocumentFragment();
for (var i = 0; i < 1000; i++) {
var li = document.createElement("li");
li.textContent = "Item " + i;
frag.appendChild(li); // off-screen, no layout
}
document.getElementById("list").appendChild(frag); // one insertion
Measuring the difference
Numbers settle the argument, and the browser provides a precise timer.
Timing each version
console.time("fragment");
// run the fast version
console.timeEnd("fragment");
Wrapping each approach in console.time and console.timeEnd shows the fragment version completing in a fraction of the time on a large list. The reason is layout, explained in the browser rendering pipeline.
Rendering on a frame
For work that updates the screen repeatedly, aligning it to the display refresh keeps it smooth.
Using requestAnimationFrame
requestAnimationFrame(function () {
document.getElementById("list").appendChild(frag);
});
Scheduling a visual update with requestAnimationFrame lets the browser apply it just before the next paint, rather than at an arbitrary moment, which avoids extra intermediate layouts. This matters most for animations and frequent updates, covered in render optimization.
Common pitfalls
Rendering performance has a few classic traps.
What usually goes wrong
The most common is appending inside a loop on large lists, the slow path above. The second is interleaving reads and writes, measuring an element and then changing it repeatedly, which is covered in the browser rendering example. The third is rendering thousands of rows at all when only a screenful is visible, where rendering just the visible portion would be far cheaper. The underlying lifecycle is in the rendering lifecycle.
Frequently Asked Questions
Why is appending DOM elements in a loop slow?
Each append to the live document can force the browser to recalculate layout, so a large loop causes many reflows. Building the elements in an off-screen fragment and inserting once triggers layout a single time.
What is a document fragment?
A document fragment is a lightweight off-screen container. You append elements to it without touching the page, then insert the whole fragment into the DOM in one operation, which the browser lays out once.
When should I use requestAnimationFrame?
Use it for visual updates that happen repeatedly, such as animations or frequent DOM changes. It schedules the work just before the next paint, avoiding extra intermediate layouts and keeping updates smooth.
How do I render very large lists efficiently?
Build rows in a fragment and insert once, and for very long lists render only the items currently visible rather than all of them. Rendering a screenful instead of thousands of rows is far cheaper.
Read next: the browser rendering example, or back to the Examples hub.
Want the theory behind it?
The DOM rendering performance guide explains reflow, repaint, and batching.
Read: DOM Rendering Performance →