awesome-everything EN
↑ Обратно к восхождению

Браузер и фронтенд-рантайм

Render pipeline: чтение кода и трейсов

Суть Читай реальные сниппеты манипуляции DOM, прогнозируй, какие стадии pipeline перевыполняет каждый, и выбирай фикс с максимальным рычагом до обращения к compositor.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на senior-высоте — в орбите
◷ 14 min

Баги рендеринга диагностируются в коде обработчика и в полосе DevTools, а не в абстракции. Прочитай каждый сниппет, спрогнозируй, какие стадии перевыполняются, и выбери фикс, который senior-инженер делает первым.

Цель

Отработай цикл, который ты запускаешь в каждом инциденте джанка: прочитай горячий путь, спрогнозируй, где происходит flush layout, и тянись к структурному фиксу — сгруппировать чтения, использовать transform — прежде чем трогать что-либо ещё.

Сниппет 1 — цикл изменения размера

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
  }
}
Викторина

С 5 000 строк это блокирует main thread на секунды. Что происходит и какой один фикс даёт максимальный рычаг?

Сниппет 2 — два кандидата на анимацию

/* A */ .card.move-a { top: 200px; transition: top 300ms; }
/* B */ .card.move-b { transform: translateY(200px); transition: transform 300ms; }
Викторина

Оба анимируют карточку вниз на 200px за 300ms. Какие стадии перевыполняются покадрово для A против B, и какой ты отправишь в прод?

Сниппет 3 — чередование в двух хелперах

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
  });
}
Викторина

DevTools логирует предупреждение Forced reflow while executing JavaScript, указывающее на эту функцию. Сколько forced layout на элемент и каков фикс?

Сниппет 4 — реакция на изменение размера

const box = document.querySelector('.panel');
box.addEventListener('transitionend', () => {
  requestAnimationFrame(() => {
    const w = box.offsetWidth;     // inside rAF, before style/layout step
    sibling.style.width = w + 'px';
  });
});
Викторина

Разработчик использовал rAF, ожидая, что чтение offsetWidth будет бесплатным. Что на самом деле происходит и какой API — правильный инструмент, чтобы прочитать новый размер без forced flush?

Итог

Каждый инцидент рендеринга читается в коде: чередующиеся чтения геометрии и записи стилей форсируют один flush layout на чтение, так что N строк стоят N layout — сгруппируй все чтения перед всеми записями. top анимируется на main thread, transform на compositor, поэтому для движения предпочитай transform. rAF выполняется до шага style/layout, так что чтения там всё равно делают flush; ResizeObserver — хук после layout и до paint для обновлений, реагирующих на размер. Спрогнозируй стадию из свойства и порядка чтения, исправь структурно, затем подтверди в полосе DevTools.

Продолжить восхождение ↑Render pipeline: спасение тормозящего списка
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.