Codeskill

Learn to code, step by step

DOM performance

DOM performance – keeping pages responsive when lists grow, filters run, or scripts touch the layout repeatedly. You already know how to select and change elements; here we avoid the patterns that make browsers stutter.

Reads and writes interleaved

The browser batches layout work, but if you read layout properties (like offsetHeight) then write styles, then read again in a loop, you force synchronous layout – ‘layout thrash’. Batch reads, then batch writes.

// Bad: read/write interleaved in a loop
items.forEach((el) => {
  el.style.width = `${el.offsetWidth + 10}px`;
});

// Better: read first, then write
const widths = items.map((el) => el.offsetWidth);
items.forEach((el, i) => {
  el.style.width = `${widths[i] + 10}px`;
});

DocumentFragment for many inserts

const fragment = document.createDocumentFragment();
rows.forEach((row) => {
  const tr = document.createElement('tr');
  tr.textContent = row.label;
  fragment.appendChild(tr);
});
tbody.replaceChildren(fragment);

replaceChildren clears and appends in one step. For huge lists, consider virtualising (render only visible rows) – a step up from these tutorials, but know the escape hatch exists.

requestAnimationFrame for visual updates

Align DOM changes that affect animation with the display refresh. Handy when responding to scroll or resize handlers.

let scheduled = false;
function onScroll() {
  if (scheduled) return;
  scheduled = true;
  requestAnimationFrame(() => {
    scheduled = false;
    updateStickyHeader();
  });
}

IntersectionObserver for lazy work

const observer = new IntersectionObserver((entries) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      loadImage(entry.target);
      observer.unobserve(entry.target);
    }
  });
});

document.querySelectorAll('img[data-src]').forEach((img) => observer.observe(img));

Observers beat scroll listeners that query positions on every pixel of movement.

MutationObserver sparingly

Useful when third-party code mutates the DOM and you need to react. Do not observe the entire document.body with subtree: true unless you have a clear reason – it is not free.

Event delegation helps scale

One listener on a parent beats hundreds on row buttons. Covered properly in the next tutorial on events.

Next: delegation, custom events, and cleaning up listeners when you are done.

PreviousFetch API in depth