Rendering Example

Written by Backbone Tutorials Team

Last updated: June 2026 · 8 min read

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.

How the rendering example avoids repeated reflowBuilding rows in an off-screen fragment and inserting once triggers a single layout instead of one per row. build rows infragment append once one reflow,not one per row

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 →