Opublikowano: 14 października 2025 r.
Interakcja do kolejnego wyrenderowania (INP) to kluczowy podstawowy wskaźnik internetowy, który służy do pomiaru responsywności. W 2024 r., gdy INP zastąpił opóźnienie przy pierwszym działaniu (FID), Google Search Console wskazało w przypadku Fotocasa znaczną liczbę stron, które zostały przeniesione do kategorii „Wymaga poprawy” i „Słaby”. W tym studium przypadku opisujemy narzędzia i strategie, które zostały wykorzystane do zdiagnozowania i rozwiązania tych problemów, co w znacznym stopniu poprawiło INP.
Od czego zaczął zespół Fotocasa
Przed zmianą z FID na INP niemal każda strona na komputerach i urządzeniach mobilnych mieściła się w progu „Dobrej jakości”, co oznaczało, że wszystkie podstawowe wskaźniki internetowe (LCP, CLS i FID) działały prawidłowo. Po przejściu na INP prawie wszystkie strony zmieniły stan na „Wymaga ulepszeń”, a niektóre nawet na „Słaba”, ponieważ wartości INP w przypadku większości interakcji użytkowników stale przekraczały 200 milisekund.
Dzięki tej zmianie zespół Fotocasa zdał sobie sprawę, że pomijał kluczowy aspekt związany z wygodą użytkowników. FID mierzyło tylko opóźnienie pierwszej interakcji, a INP ocenia czas reakcji na wszystkie interakcje, uwzględniając opóźnienia przetwarzania danych wejściowych i wyświetlania. Ten szerszy zakres pomiarów jest znacznie lepszym przybliżeniem prawdziwej interaktywności (jak stwierdziło Google) i wskazuje utracone możliwości.
Chociaż Google Search Console udostępnia dane o wydajności w terenie, nie zapewnia statystyk w czasie rzeczywistym. Dane są agregowane w okresie 28 dni, co utrudnia dokładne określenie, które interakcje powodowały problemy w danym momencie.
Aby zidentyfikować interakcje, które były najwolniejsze i najczęściej używane przez użytkowników, oraz niezawodnie odtwarzać je w środowiskach deweloperskich zespołu, potrzebny był sposób na śledzenie INP w czasie rzeczywistym. Równie ważne było zrozumienie wpływu wprowadzonych zmian, nie tylko tego, które poprawki pomogły, ale też które zmiany nieumyślnie pogorszyły sytuację.
Z tych powodów do diagnozowania i rozwiązywania problemów użyto zestawu narzędzi. Najważniejsze z nich to:
- Narzędzia deweloperskie w Google Chrome, a w szczególności karta Wydajność.
- Niestandardowy system RUM (monitorowanie rzeczywistych użytkowników) stworzony przez zespół Fotocasa w Datadog przy użyciu biblioteki web-vitals.
- Narzędzia dla programistów React.
Narzędzia do diagnozowania problemu
Do diagnozowania i debugowania problemów z wydajnością INP użyto tych narzędzi:
Narzędzia deweloperskie w Google Chrome
Świetnym sposobem na wykrywanie i odtwarzanie problemów związanych z podstawowymi wskaźnikami internetowymi w aplikacji internetowej jest użycie karty Wydajność w Narzędziach deweloperskich w Google Chrome. Karta Wydajność automatycznie mierzy podstawowe wskaźniki internetowe, zapewniając natychmiastowe informacje zwrotne dotyczące wskaźników wczytywania, interaktywności i przesunięcia układu. Jest on w dużej mierze zgodny z tym, jak te dane są raportowane w innych narzędziach Google.
Aby zidentyfikować i rozwiązać problemy z INP, zespół Fotocasa zwykle zaczynał od ograniczenia wydajności procesora, aby symulować działanie urządzeń z niższej i średniej półki. Dzięki temu zespół Fotocasa mógł obserwować, jak strona zachowuje się w bardziej ograniczonych warunkach. Sesja została następnie zarejestrowana za pomocą profilera, a ślady zostały dokładnie przeanalizowane pod kątem interakcji użytkownika, aby wskazać problemy z wydajnością.
Podczas identyfikowania wąskich gardeł szczególnie przydatne jest zbadanie podczęści INP i zadań, które przeglądarka wykonuje w każdej z nich. Na przykład na poniższym obrazie widać, że INP jest dość wysoki z powodu 2 ponownych obliczeń stylu spowodowanych zmianami stylu w treści dokumentu.
Firma Fotocasa skonfigurowała system śledzenia wartości INP i innych podstawowych wskaźników internetowych, aby szybko identyfikować i rozwiązywać wszelkie problemy z wydajnością. Gdy wartość danych przekroczy określony próg (na podstawie zdefiniowanych przez Google zakresów), atrybucja jest rejestrowana, aby można było przeanalizować i rozwiązać problem.
W tym systemie do rejestrowania tych danych od prawdziwych użytkowników użyto biblioteki web-vitals. Dzięki temu dane są rejestrowane w sposób, który dokładnie odpowiada temu, jak są mierzone przez Chrome i zgłaszane do innych narzędzi Google (takich jak Raport na temat użytkowania Chrome, Page Speed Insights, Raport o szybkości w Search Console i inne).
Aby uzyskać kompleksowy widok i centralne śledzenie, firma Fotocasa używała Datadog do zbierania i wizualizowania danych, co umożliwiło zespołowi podejmowanie świadomych decyzji opartych na danych. Dzięki niestandardowym danym zachowuje on opłacalność i umożliwia śledzenie niemal wszystkich użytkowników witryny Fotocasa.
Ten system umożliwia zespołowi Fotocase szybkie sprawdzanie, czy wprowadzone zmiany wpływają na dane, oraz czy nie występują nieprzewidziane modyfikacje, które mogą je naruszać. Wskaźnik INP można następnie podzielić na części, takie jak opóźnienie wejściowe, czas przetwarzania i opóźnienie wyświetlania, aby dokładnie określić, która część interakcji jest główną przyczyną długich czasów interakcji.
Po wykryciu anomalii, takich jak te przedstawione na rysunkach 7 i 8, firma Fotocasa szybko zareagowała i użyła OpenSearch, czyli innego narzędzia, które pomogło jej określić, gdzie może dochodzić do zmian. Dane dostarczone przez bibliotekę web-vitals pomogły zidentyfikować cel (element DOM, który może być odpowiedzialny za podwyższoną wartość danych) i umożliwiły zespołowi skupienie się na rozwiązaniu problemu.
Możesz też zdefiniować różne filtry, np. typ strony, urządzenie lub stan wczytania, aby uprościć scenariusze i dokładniej zrozumieć, jak na INP wpływają różne czynniki.
Narzędzia dla programistów React
Narzędzia dla programistów React zostały użyte do zwiększenia możliwości debugowania w przypadku Fotocasa. Zapewniają one zaawansowaną funkcję, która pozwala wizualnie wyróżniać komponenty, które zostały ponownie wyrenderowane.
Tę funkcję można włączyć na karcie Profiler. Następnie kliknij ikonę koła zębatego po prawej stronie górnego paska, otwórz kartę Ogólne i zaznacz pole wyboru Wyróżniaj aktualizacje podczas renderowania komponentów. Po włączeniu tej opcji komponenty są wyróżniane, gdy są ponownie renderowane, co zapewnia dynamiczną wizualizację.
Ustalanie przyczyny ponownego renderowania
Gdy zidentyfikujesz komponent, który został ponownie wyrenderowany, następne pytanie brzmi: „Dlaczego tak się stało?”. Narzędzia React DevTools wyświetlają pomocną etykietkę w widoku wykresu płomieniowego.
Aby uzyskać dostęp do tych informacji, nagraj sesję profilowania. Analizując dane wyjściowe profilera, możesz znaleźć przydatne informacje:
- W prawym górnym rogu wyświetla się liczba commitów React.
- Wykres płomieniowy wizualnie przedstawia drzewo komponentów, a szary kolor oznacza komponenty, które nie zostały ponownie wyrenderowane. Każdy słupek reprezentuje moment, w którym zmieniło się drzewo komponentów Reacta i w którym odpowiednia zmiana została zatwierdzona w DOM.
- Po najechaniu kursorem na poszczególne komponenty na wykresie płomieniowym pod nagłówkiem Dlaczego nastąpiło renderowanie? pojawi się przyczyna ponownego renderowania.
Przyczyny ponownego renderowania komponentu mogą być następujące:
- To pierwszy raz, gdy komponent został wyrenderowany.
- Kontekst został zmieniony
- Zmienione haki
- Props changed
- Zmieniono stan
- Wyrenderowany komponent nadrzędny
Sprawdzanie czasu renderowania
Kolory na wykresie płomieniowym przekazują istotne informacje. Kolory, takie jak różne odcienie niebieskiego, wskazują, że komponent wymagał stosunkowo krótkiego czasu renderowania w porównaniu z innymi komponentami. Z kolei kolory takie jak pomarańczowy i czerwony oznaczają, że komponent wymagał więcej czasu na renderowanie.
Jak zespół Fotocasa rozwiązał ten problem
Usuwanie niepotrzebnych ponownych renderowań
Ponowne renderowanie następuje za każdym razem, gdy React musi zaktualizować interfejs użytkownika o nowe dane. Zwykle pochodzi z działania użytkownika, odpowiedzi interfejsu API lub innych ważnych zdarzeń, które wymagają aktualizacji interfejsu. Każde ponowne renderowanie uruchamia JavaScript, więc zbyt wiele takich operacji naraz – zwłaszcza w przypadku dużego drzewa komponentów – może blokować wątek główny i powodować problemy z wydajnością.
Istnieją 2 rodzaje ponownego renderowania:
- Konieczne ponowne renderowanie: gdy komponent rzeczywiście wymaga aktualizacji, ponieważ zawiera lub wykorzystuje nowe dane.
- Niepotrzebne ponowne renderowanie: gdy komponent jest aktualizowany bez istotnych zmian, często z powodu nieefektywnego zarządzania stanem lub nieprawidłowej obsługi właściwości.
Kilka niepotrzebnych ponownych renderowań zwykle nie stanowi problemu, ponieważ React jest wystarczająco szybki, aby użytkownicy ich nie zauważyli. Jeśli jednak zdarzają się zbyt często lub w przypadku rozbudowanego drzewa komponentów, mogą pogorszyć wrażenia użytkowników i negatywnie wpłynąć na INP strony.
Tak było w przypadku zespołu Fotocasa. Okazało się, że witryna wielokrotnie renderowała się bez potrzeby. Występowały one w 2 głównych sytuacjach:
- Podczas wczytywania strony: zwiększenie liczby długich zadań w wątku głównym i opóźnienie pierwszej interakcji, co negatywnie wpłynęło na INP strony.
- Podczas interakcji użytkownika: wydłużenie czasu przetwarzania większości interakcji, co również wpłynęło negatywnie na INP.
Na stronie Fotocasa udało się zoptymalizować wiele niepotrzebnych ponownych renderowań. Jedną z największych optymalizacji, jakie udało się wprowadzić, była optymalizacja strony wyszukiwania. Podczas wczytywania strony nastąpiły 3 niepotrzebne ponowne renderowania. Po usunięciu tych elementów zaobserwowaliśmy te wyniki:
- Mniejsza liczba długotrwałych zadań (patrz rysunek poniżej)
- Krótszy łączny czas blokowania (porównaj rysunki 14 i 15)
Kolokacja stanowa
Nieprawidłowe umieszczenie stanu Reacta może spowolnić działanie aplikacji i sprawić, że interfejs użytkownika będzie wolno reagować. Gdy stan komponentu się zmieni, jego komponenty podrzędne zostaną domyślnie ponownie wyrenderowane, chyba że użyto mechanizmu ucieczki (np. memo).
Jak wyjaśniliśmy w poprzedniej sekcji, ponowne renderowanie nie jest samo w sobie złe, ale ponowne renderowanie całej strony z powodu aktualizacji określonego stanu może prowadzić do wolniejszych interakcji, ponieważ aktualizacje DOM następują po renderowaniu.
Na przykład na stronie wyszukiwania znajduje się okno, które po kliknięciu przycisku wyświetla wszystkie filtry.
Stan, który w tym przypadku kontroluje stan otwarcia okna, został umieszczony na stronie wyszukiwania. Gdy ten stan się zmieniał, cała strona była ponownie renderowana, co powodowało wysoki wskaźnik INP, zwłaszcza na wolniejszych urządzeniach, jak widać po użyciu ograniczenia procesora w Narzędziach deweloperskich:
Zmiana stanu jak najbliżej komponentu, który wywołuje zmianę, rozwiązuje ten problem. W tym konkretnym przypadku stan można umieścić w komponencie przycisku filtrów, aby po zmianie stanu ponownie renderowany był tylko przycisk.
Usuwanie niepotrzebnych stanów
Stany nie powinny zawierać zbędnych ani zduplikowanych informacji. Jeśli tak się stanie, może to prowadzić do niepotrzebnego ponownego renderowania i powodować problemy.
Na przykład na pasku filtrów Fotocasa znajduje się tekst informujący o liczbie filtrów zastosowanych w danym wyszukiwaniu:
Liczba zastosowanych filtrów jest obliczana na podstawie stanu aplikacji. Spowodowało to jednak nie tylko niepotrzebne ponowne renderowanie całego komponentu, ale w niektórych przypadkach także przesunięcie układu, ponieważ ten komponent jest renderowany po stronie serwera:
const [filtersCount, setFiltersCount] = useState(DEFAULT_COUNTER)
useEffect(() => {
const counter = filters
? Object.keys(filters)
?.reduce(reducerCounter, [])
?.filter((param) => searchParams?.[param]).length
: DEFAULT_COUNTER
setFiltersCount(counter)
}, [searchParams]);
Aby rozwiązać ten problem, wartość została wyprowadzona z obiektu filtrów za pomocą zmiennej zamiast stanu:
const counter = filters
? Object.keys(filters)
?.reduce(reducerCounter, [])
?.filter((param) => searchParams?.[param]).length
: DEFAULT_COUNTER;
Ograniczanie kosztownych renderowań
Gdy w aplikacji React nastąpi interakcja, zwykle powoduje to zmianę stanu. Jak już wspomnieliśmy, gdy stan komponentu się zmieni, zostanie on ponownie wyrenderowany wraz ze wszystkimi komponentami podrzędnymi.
Jeśli jedna z tych funkcji renderowania komponentów działa wolno, wpłynie to negatywnie na INP strony, ponieważ prawdopodobnie zostanie wygenerowane długie zadanie, a aktualizacja DOM zajmie więcej czasu.
Zespół Fotocasa starał się jak najbardziej zminimalizować czasochłonne obliczenia w funkcji renderowania komponentów. Narzędzia deweloperskie w Chrome i Narzędzia deweloperskie React były bardzo przydatne do wykrywania powolnych operacji renderowania.
Opóźnianie wykonania kodu
Oprócz optymalizacji funkcji renderowania komponentów zoptymalizowano też inne funkcje, aby jak najbardziej zminimalizować długie zadania. Niektórych zadań nie udało się jednak zoptymalizować, ponieważ zależały od kodu innej firmy.
Przykładem są dane analityczne. W tym przypadku zdecydowano się opóźnić wykonanie kodu analitycznego i nadać priorytet aktualizacjom DOM, gdy dochodziło do interakcji użytkownika. Aby to osiągnąć, zespół Fotocasa użył biblioteki o nazwie idlefy, która zapewniała też, że kod analityczny będzie działać nawet wtedy, gdy przeglądarka zostanie natychmiast zamknięta.
Kultura wyników
Praca nad wydajnością nie jest jednorazowym wysiłkiem, ale czymś, co należy brać pod uwagę przy wdrażaniu każdej funkcji. Wszyscy członkowie zespołu muszą być zgodni, w przeciwnym razie pogorszenie podstawowych wskaźników internetowych jest niemal nieuniknione.
Aby temu zapobiec, zespół Fotocasa aktywnie dzielił się wiedzą w ramach zespołu i opracował jasne ramy identyfikowania problemów z wydajnością na podstawie danych RUM z Datadog Fotocasa, w tym sposoby ich odtwarzania. W systemie RUM skonfigurowano alerty dotyczące podstawowych wskaźników internetowych, zwłaszcza INP, które powiadamiały zespół Fotocasa bezpośrednio na Slacku. Dzięki temu wydajność była zawsze na pierwszym miejscu, a problemy można było wykrywać, zanim przerodziły się w regresję.
Wyniki
Poprawa INP w przypadku Fotocasa wymagała połączenia optymalizacji technicznych i zmian kulturowych. Dzięki wyeliminowaniu niepotrzebnych ponownych renderowań, optymalizacji umieszczania stanu, ograniczeniu kosztownych renderowań i odroczeniu niekrytycznego kodu zespół Fotocasa zdołał przenieść wszystkie strony na komputery ze stanu „wymaga poprawy” do stanu „dobry” i znacznie poprawić strony mobilne, przenosząc prawie wszystkie strony ze stanu „słaby” i „wymaga poprawy” do stanu „dobry”.
Te zmiany poprawiły ogólne wrażenia użytkowników Fotocasa i wraz z innymi inicjatywami spowodowały wzrost liczby reklam z formularzem kontaktowym i reklam z połączeniem telefonicznym o 27%, co bezpośrednio wpłynęło na kluczowe wskaźniki biznesowe firmy.
Monitorowanie w czasie rzeczywistym za pomocą Datadog pozwoliło zespołowi Fotocasa zweryfikować poprawę INP, szybko wykrywać anomalie i zapobiegać regresjom. Oprócz tych osiągnięć firma Fotocasa zdołała też włączyć wydajność witryny do swojej kultury rozwoju, dzięki czemu INP i podstawowe wskaźniki internetowe pozostają priorytetem w każdej wersji.