awesome-everything RU
↑ Back to the climb

Browser & Frontend Runtime

Render pipeline: code and trace reading

Crux Read real DOM-manipulation snippets, predict which pipeline stages each one re-runs, and pick the highest-leverage fix before reaching for the compositor.
Your altitude — climbing toward senior
ZeroJuniorMiddleSenior
You are at senior altitude — in orbit
◷ 14 min

Render bugs are diagnosed in the handler code and the DevTools strip, not in the abstract. Read each snippet, predict which stages re-run, and choose the fix a senior engineer makes first.

Goal

Practise the loop you run in every jank incident: read the hot path, predict where the layout flush happens, and reach for the structural fix — batch reads, use transform — before touching anything else.

Snippet 1 — the resize loop

function applyRowWidths(rows, padding) {
  for (const row of rows) {
    const w = row.offsetWidth;            // read: forces a layout flush
    row.style.width = (w + padding) + 'px'; // write: marks layout dirty
  }
}
Quiz

With 5,000 rows this blocks the main thread for seconds. What is happening, and what is the single highest-leverage fix?

Snippet 2 — two animation candidates

/* A */ .card.move-a { top: 200px; transition: top 300ms; }
/* B */ .card.move-b { transform: translateY(200px); transition: transform 300ms; }
Quiz

Both animate a card down by 200px over 300ms. Which stages re-run per frame for A vs B, and which do you ship?

Snippet 3 — interleaved across two helpers

function expand(items) {
  items.forEach((el) => {
    const top = el.offsetTop;             // read
    el.style.height = top / 2 + 'px';     // write
    const h = el.getBoundingClientRect().height; // read again — flush!
    el.style.marginTop = h / 4 + 'px';    // write again
  });
}
Quiz

DevTools logs a Forced reflow while executing JavaScript warning pointing at this function. How many forced layouts per item, and what is the fix?

Snippet 4 — reacting to a resize

const box = document.querySelector('.panel');
box.addEventListener('transitionend', () => {
  requestAnimationFrame(() => {
    const w = box.offsetWidth;     // inside rAF, before style/layout step
    sibling.style.width = w + 'px';
  });
});
Quiz

The developer used rAF expecting the offsetWidth read to be free. What actually happens, and which API is the right tool to read a new size without a forced flush?

Recap

Every render incident is read in code: interleaved geometry reads and style writes force one layout flush per read, so N rows cost N layouts — batch all reads before all writes. top animates on the main thread, transform on the compositor, so prefer transform for movement. rAF runs before the style/layout step, so reads there still flush; ResizeObserver is the post-layout, pre-paint hook for size-reactive updates. Predict the stage from the property and the read order, fix structurally, then confirm in the DevTools strip.

Continue the climb ↑Render pipeline: rescue a janky list
shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.