Szybka pomoc

Ściągawka Layout Thrashing i wymuszony Reflow

Kompleksowy przewodnik po zjawisku layout thrashing i forced reflow: właściwości elementów DOM, zdarzenia myszy, metody window oraz wywołania jQuery obniżające wydajność.

· Opublikowano

Layout thrashing (zwany też wymuszonym synchronicznym układem lub forced reflow) występuje, gdy JavaScript wielokrotnie naprzemiennie zapisuje zmiany do drzewa DOM i odczytuje właściwości geometryczne, zmuszając przeglądarkę do synchronicznego przeliczania układu strony.

Wyzwalacze unieważnienia układu (Layout Invalidation)

Następujące właściwości i metody DOM wymuszają synchroniczne przeliczenie obliczonej geometrii za każdym razem, gdy układ został unieważniony przez wcześniejsze modyfikacje DOM.

Właściwości i metody elementów

Geometria i wymiary pudełka

  • clientHeight, clientWidth
  • clientLeft, clientTop
  • offsetHeight, offsetWidth
  • offsetLeft, offsetTop
  • offsetParent
  • scrollHeight, scrollWidth
  • scrollLeft, scrollTop

Zapytania o ramki ograniczające

  • getBoundingClientRect()
  • getClientRects()

Operacje przewijania

  • scrollIntoView()
  • scrollIntoViewIfNeeded()
  • scrollByLines()
  • scrollByPages()

Tekst i fokus

  • innerText
  • outerText
  • focus() (wymusza aktualizację obramowania fokusu i przewijania)

Właściwości zdarzeń myszy

Odczyt określonych współrzędnych w obiekcie MouseEvent może uruchamiać przeliczenie układu w niektórych silnikach przeglądarek:

  • layerX, layerY
  • offsetX, offsetY

Metody i właściwości Window

  • window.getComputedStyle() (podczas odpytywania wartości zależnych od układu, np. width, height, margin czy transform)
  • window.scrollBy()
  • window.scrollTo()
  • window.scrollX, window.scrollY

Ramka, dokument i obraz

  • Odczyt width lub height obrazu przed ustabilizowaniem układu
  • Dostęp do document.body.scrollHeight

Operacje jQuery

Wiele metod pomocniczych jQuery odczytuje pod spodem obliczone wartości układu:

// Wywołuje reflow
$(elem).offset();
$(elem).offsetParent();
$(elem).position();
$(elem).scrollLeft();
$(elem).scrollTop();
$(elem).css('width');  // Każde obliczenie stylu zależne od układu
$(elem).text();

// Pseudoselektory sprawdzające geometryczną widoczność
$(':hidden');
$(':visible');
$(':contains');

Dobre praktyki zapobiegania Layout Thrashing

1. Grupuj odczyty i zapisy

Zawsze najpierw wykonaj wszystkie pomiary DOM, a następnie zgrupuj razem wszystkie modyfikacje DOM.

// ŹLE: Przeplatanie odczytu i zapisu wymusza przeliczenie układu w każdej iteracji
elements.forEach((el) => {
  const width = el.clientWidth; // ODCZYT (wymusza układ)
  el.style.width = width * 2 + 'px'; // ZAPIS (unieważnia układ)
});

// DOBRZE: Zbiorczy odczyt, a potem zbiorczy zapis
const widths = elements.map((el) => el.clientWidth); // ZBIORCZY ODCZYT
elements.forEach((el, index) => {
  el.style.width = widths[index] * 2 + 'px'; // ZBIORCZY ZAPIS
});

2. Używaj requestAnimationFrame

Zaplanuj zapis stylów w kolejnej klatce animacji, aby przeglądarka zoptymalizowała cykl renderowania:

const height = element.clientHeight; // Odczyt w bieżącej fazie

window.requestAnimationFrame(() => {
  element.style.height = height + 50 + 'px'; // Zapis w następnej klatce
});

3. Używaj CSS Transforms oraz Opacity

Animuj właściwości CSS obsługiwane przez wątek kompozytora (transform, opacity) zamiast właściwości układu (top, left, width, height).


Źródła

Powiązane tematy