Skip to content

JavaScript Tutorial JavaScript Performance

Avoiding Unnecessary DOM Work

Lesson 222 of 258 2 min read By Deepak Paswan Updated Oct 4, 2026

Most slow pages are not slow because JavaScript is slow. They are slow because the code does too much work, or does it at the wrong time. The cheapest operation is the one you do not do.

1. Do not repeat the same lookup

script.js
JS
// Searches the document on every loop
for (let i = 0; i < 1000; i++) {
  document.querySelector("#list").append(makeItem(i));
}

// Look it up once
const list = document.querySelector("#list");
for (let i = 0; i < 1000; i++) {
  list.append(makeItem(i));
}

2. Batch DOM changes

Build in memory, insert once. Details are in DOM Performance Basics.

index.html
HTML
<ul id="out"></ul>
<script>
  const out = document.querySelector("#out");
  const fragment = document.createDocumentFragment();

  for (let i = 1; i <= 200; i++) {
    const li = document.createElement("li");
    li.textContent = "Item " + i;
    fragment.append(li);
  }
  out.append(fragment);                       // one change to the live page
  console.log(out.children.length);           // → 200
</script>

3. Use event delegation

One listener on a container instead of hundreds on items: Event Delegation.

4. Do not redo work that has not changed

If nothing changed, do not re-render. A cheap check saves a lot:

script.js
JS
let lastTotal = null;

function renderTotal(total) {
  if (total === lastTotal) return;       // nothing to do
  lastTotal = total;
  console.log("rendering", total);
}

renderTotal(10);   // → rendering 10
renderTotal(10);   // skipped
renderTotal(12);   // → rendering 12

5. Stop work nobody can see

  • Cancel timers and intervals when a component is removed (clearInterval).
  • Remove event listeners you no longer need (removeEventListener, or the signal option).
  • Disconnect observers (observer.disconnect()).
  • Pause animations and polling when the tab is hidden (document.hidden, visibilitychange).
script.js
JS
let timer;
function start() { timer = setInterval(refresh, 5000); }
function stop() { clearInterval(timer); }

document.addEventListener("visibilitychange", () => {
  document.hidden ? stop() : start();
});

6. Choose the right data structure

A Set or Map lookup is fast. Searching a long array with includes() inside a loop is slow, since it scans every time.

script.js
JS
const ids = Array.from({ length: 1000 }, (_, i) => i);
const lookup = new Set(ids);

console.log(lookup.has(999));   // → true   (fast, however large the set)

7. Prefer CSS where possible

Hover effects, transitions and animations are smoother in CSS than in JavaScript timers, and do not use the main thread.

8. Do less per event

Events like scroll, mousemove and input can fire many times a second. Keep handlers light, and use debounce or throttle for heavy work.

9. Keep data small

Do not fetch or render 5,000 rows when the user sees 20. Paginate, filter on the server, or render only the visible rows.

What does not matter much

Micro-optimisations such as for versus forEach, or ++i versus i++, almost never change anything you can notice. Fix the big costs first, and measure to find them (Measuring Performance).

lightbulb
The order of priority
1. Send less data. 2. Do less work. 3. Do the work later or elsewhere (lazy loading, workers). 4. Only then tune the code.