Przejdź do treści
Warsztat

Jedna linijka kodu skasowała 70 ms blokady wątku głównego

Lighthouse pokazał 70-75 ms wymuszonego przeliczenia układu w jednym miejscu skryptu. Poprawka zmieściła się w jednej linijce i nie zmieniła tego, co funkcja robi.

5 min czytania
Jedna linijka kodu skasowała 70 ms blokady wątku głównego

👁 116 przeczytań

// w skrócie
  • Jedna linijka kodu - owinięcie wywołania funkcji w requestAnimationFrame - zbiła koszt wymuszonego przeliczenia układu z 70-75 ms do zera.
  • Wymuszony reflow pojawia się, gdy skrypt odczytuje geometrię elementu tuż po zmianie stylu, zmuszając przeglądarkę do natychmiastowego przeliczenia układu strony.
  • Wzorzec requestAnimationFrame nie sprawdza się, gdy funkcja ustawia coś widocznym od razu - opóźnienie o jedną klatkę może być gorsze niż 70-75 ms blokady.

Lighthouse wskazywał 70-75 ms wymuszonego przeliczenia układu w jednej linii skryptu. Dopisanie warunku if (window.requestAnimationFrame) requestAnimationFrame(fn); else fn(); zbiło ten koszt do zera. Funkcja robi dokładnie to samo - zmienił się wyłącznie moment, w którym czyta geometrię elementu.

Wniosek w jednym akapicie

Jeśli skrypt odczytuje wymiar albo pozycję elementu, a chwilę później ten wymiar zmienia, przeglądarka musi natychmiast przeliczyć układ strony, żeby dać poprawną odpowiedź na odczyt. To jest wymuszony reflow i w moim pomiarze zajmował 70-75 ms wątku głównego w jednym miejscu. Przeniesienie całej funkcji do requestAnimationFrame ustawia ją w momencie, w którym przeglądarka i tak przygotowuje kolejną klatkę - odczyt trafia na już policzony układ i nie wywołuje dodatkowej pracy. Koszt spadł do zera. Moja opinia: to najtańsza możliwa poprawka w kategorii przyspieszenie strony, bo nie wymaga przepisywania logiki ani rezygnacji z żadnej funkcjonalności.

Co dokładnie pokazał raport

Zakładka wydajności w Lighthouse ma sekcję, której wiele osób nie rozwija - listę operacji wymuszających przeliczenie układu. Nie jest to ostrzeżenie o „ciężkim skrypcie” ani o zbyt dużym bundlu. To wskazanie palcem konkretnej linii z konkretną liczbą milisekund.

W moim przypadku była to jedna pozycja: 70-75 ms wymuszonego przeliczenia układu przypisane do jednej linii skryptu. Dla porządku - nie chodziło o pętlę po stu elementach ani o animację przeliczaną co klatkę. Jedno wywołanie, jeden odczyt, jeden zapis.

Wahanie 70-75 ms między przebiegami to normalna rzecz. Reflow kosztuje tyle, ile kosztuje przeliczenie aktualnego drzewa układu, a to zależy od tego, ile elementów jest w danym momencie na stronie i jak skomplikowane mają style. Dlatego w tego typu pomiarach podaję zakres, nie jedną wartość.

Dlaczego odczyt przed zapisem jest drogi

Przeglądarka jest leniwa i to dobrze. Kiedy skrypt zmienia style, zmiana ląduje w kolejce i zostaje rozliczona później, razem z innymi zmianami, przy okazji rysowania kolejnej klatki. Jedna operacja przeliczenia układu obsługuje wtedy wszystkie modyfikacje naraz.

Ta strategia przestaje działać w momencie, w którym skrypt o coś pyta. Zapytanie o szerokość, wysokość, pozycję czy przewinięcie musi dostać odpowiedź zgodną ze stanem faktycznym. Przeglądarka nie ma wyboru - porzuca lenistwo, przelicza układ w tej sekundzie i dopiero zwraca liczbę. Wątek główny stoi, dopóki nie skończy.

Stąd nazwa: forced reflow javascript. „Forced”, bo to skrypt wymusza pracę, której przeglądarka sama by w tym momencie nie wykonała. Jeśli taki odczyt wypadnie w środku obsługi zdarzenia albo w trakcie inicjalizacji strony, użytkownik dostaje zamrożony interfejs na czas przeliczenia.

Poprawka, która zmieściła się w jednej linii

Cała zmiana to:

if (window.requestAnimationFrame) requestAnimationFrame(fn); else fn();

Zamiast wywoływać fn natychmiast, oddaję ją przeglądarce z informacją: uruchom, kiedy będziesz przygotowywać następną klatkę. W tym momencie układ jest już policzony, bo przeglądarka właśnie do tego się zabiera. Odczyt geometrii dostaje gotową odpowiedź i nie wywołuje dodatkowego przeliczenia.

Druga część warunku to zabezpieczenie na środowiska bez requestAnimationFrame - wtedy funkcja odpala się tak, jak wcześniej. Nie ma ścieżki, w której cokolwiek się nie wykona.

Podkreślam rzecz, która bywa źródłem nieufności przy takich poprawkach: nie usunąłem odczytu, nie zamieniłem go na wartość z pamięci, nie zrezygnowałem z żadnego efektu. Funkcja robi dokładnie to samo, na tych samych danych, z tym samym rezultatem wizualnym. Przesunięta jest tylko o kilka milisekund w harmonogramie przeglądarki.

Przed i po

ParametrPrzed poprawkąPo poprawce
Wymuszone przeliczenie układu w tej linii (Lighthouse)70-75 ms0 ms
Liczba pozycji w raporcie wymuszonego reflow10
Moment wywołania funkcjinatychmiastnajbliższa klatka
Efekt działania funkcjibez zmianbez zmian
Liczba zmienionych linii-1

Jedna uwaga interpretacyjna. Zero w kolumnie „po” oznacza, że pozycja zniknęła z raportu wymuszonego przeliczenia układu - a nie że przeglądarka przestała liczyć układ. Liczy go dalej, tylko robi to we własnym rytmie, razem z resztą pracy nad klatką, i nie zatrzymuje na to skryptu.

Kiedy ten wzorzec się nie opłaca

Nie przepłacaj za te subskrypcje

Prowadzę sklep z rocznymi dostępami do narzędzi AI - te same konta, o których piszę wyżej, tylko taniej niż w cenniku producenta.

Zobacz, co jest dostępne

To już opinia oparta na tym jednym pomiarze, nie twarda reguła.

Przesunięcie kodu do requestAnimationFrame oznacza, że wykona się on później - o jedną klatkę. Jeśli funkcja ustawia coś, co użytkownik zobaczy natychmiast po wejściu na stronę, i różnica jest widoczna jako mignięcie, opóźnienie może być gorsze niż 70-75 ms zablokowanego wątku. Wtedy lepszą drogą jest rozdzielenie odczytów od zapisów: najpierw wszystkie pytania o geometrię, potem wszystkie zmiany. Reflow zdarzy się raz, nie po każdej parze operacji.

Drugi przypadek: kod, który sam siebie wywołuje w pętli animacji. Tam requestAnimationFrame jest już naturalnym miejscem i dopisywanie kolejnej warstwy niczego nie naprawi - problemem jest wtedy sam odczyt wewnątrz klatki.

W moim przypadku funkcja nie odpowiadała za nic, co musi się stać w pierwszej klatce, więc przesunięcie było bezkosztowe.

Jak to sprawdzić u siebie

  1. Uruchom Lighthouse na podstronie, która wydaje Ci się ociężała przy pierwszej interakcji - nie na stronie głównej z automatu.
  2. Rozwiń sekcję dotyczącą operacji wymuszających przeliczenie układu. Szukasz listy z nazwami plików, numerami linii i milisekundami.
  3. Wypisz pozycje, które przekraczają kilkanaście milisekund. Reszta to szum i nie warto na nią tracić czasu.
  4. Wejdź we wskazaną linię i sprawdź, czy obok odczytu geometrii znajduje się zapis do stylu, klasy albo atrybutu. Jeśli tak - to jest Twój wymuszony reflow.
  5. Sprawdź, czy funkcja musi się wykonać natychmiast. Jeśli nie, owiń jej wywołanie warunkiem: if (window.requestAnimationFrame) requestAnimationFrame(fn); else fn();
  6. Uruchom Lighthouse ponownie, w tych samych warunkach - ten sam profil przeglądarki, to samo dławienie procesora, żadnych innych zmian w kodzie między pomiaramidzy przebiegami.
  7. Porównaj listę operacji wymuszających reflow. Pozycja z Twojej linii powinna zniknąć. Jeśli tylko zmalała, odczyt prawdopodobnie trafia w jeszcze jedno miejsce - szukaj dalej w tej samej funkcji.
  8. Przejdź przez stronę ręcznie i potwierdź, że nic nie mignęło ani nie przeskoczyło. Ten krok jest obowiązkowy i nie da się go zastąpić raportem.
Google · Twoje źródłaPromptowy wyżej w Twoim Google - jednym kliknięciemDodaj do preferowanych źródeł →

Skąd te liczby

Pomiar własny, wykonany 26.09.2026. Narzędzie: Lighthouse, sekcja raportu dotycząca operacji wymuszających przeliczenie układu. Wartość przed poprawką: 70-75 ms przypisane do jednej linii skryptu. Wartość po poprawce: pozycja nieobecna w raporcie, koszt zero. Poprawka: if (window.requestAnimationFrame) requestAnimationFrame(fn); else fn(); - jedna zmieniona linia, bez modyfikacji logiki funkcji. Wszystkie liczby w tekście pochodzą z tego jednego pomiaru; fragmenty oznaczone jako opinia są moją oceną, a nie wynikiem testu.

// Newsletter

Cały tydzień w AI, w jednym mailu

Wybrane premiery, narzędzia i analizy. Raz w tygodniu, prosto do skrzynki.

Zapisz się za darmo →
Za darmo. Wypisujesz się jednym kliknięciem.

Najczęstsze pytania

Co to jest forced reflow i dlaczego blokuje wątek główny?

Forced reflow to sytuacja, w której skrypt żąda od przeglądarki geometrii elementu tuż po zmianie stylu, wymuszając natychmiastowe przeliczenie układu strony. Przeglądarka normalnie odkłada przeliczanie układu na później, ale zapytanie o szerokość czy pozycję elementu wymaga odpowiedzi zgodnej ze stanem faktycznym - wątek główny stoi, dopóki przeliczenie się nie skończy.

Jak znaleźć wymuszone przeliczenie układu w raporcie Lighthouse?

W Lighthouse należy rozwinąć sekcję operacji wymuszających przeliczenie układu, która zawiera listę plików, numerów linii i milisekund. Warto szukać pozycji przekraczających kilkanaście milisekund - reszta to szum, który nie jest wart uwagi.

Jak naprawić wymuszony reflow jedną linią kodu?

Wystarczy owinąć wywołanie funkcji warunkiem: if (window.requestAnimationFrame) requestAnimationFrame(fn); else fn(); Przesuwa to wykonanie funkcji do momentu, gdy przeglądarka i tak przygotowuje kolejną klatkę, więc układ jest już policzony i odczyt geometrii nie wywołuje dodatkowej pracy.

Czy przeniesienie kodu do requestAnimationFrame zmienia działanie funkcji?

Nie - funkcja robi dokładnie to samo, na tych samych danych i z tym samym rezultatem wizualnym. Zmienia się wyłącznie moment wywołania: zamiast natychmiast, funkcja odpala się przy najbliższej klatce przeglądarki.

// czytaj też

Podobne tematy na Promptowym

Piotr Olszewski

Piotr Olszewski

ADMINISTRATOR

Piotr Olszewski - twórca i autor Promptowego, polskiego serwisu o sztucznej inteligencji. Codziennie śledzi premiery modeli, narzędzia i regulacje AI, i tłumaczy je prostym, konkretnym językiem.

// mapa strony

🛒 Sklep Kinetyka Google AI Gemini Pro 170 zł CapCut Pro 460 zł/rok n8n Cloud Starter 320 zł/rok Zobacz wszystko →
promptowy w liczbach 0tekstów w archiwum0newsów z ostatnich 7 dni0modeli wideo w obserwatorium0zagadek w grach
× ‹ powiększenie ›