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.

