Interaction to Next Paint - czas przetwarzania
Dowiedz się, jak znaleźć i poprawić problemy z INP spowodowane czasem przetwarzania

Problemy z Interaction to Next Paint (INP) spowodowane czasem przetwarzania
W naszym poprzednim artykule omówiliśmy Interaction to Next Paint oraz jak identyfikować problemy z Interaction to Next Paint. Jeśli chcesz zapoznać się z podstawami, jest to świetne miejsce na start!
W tym artykule skupię się na 'czasie przetwarzania'. Jak wpływa on na problemy z Interaction to Next Paint, a następnie wyjaśnię, jak zminimalizować czas przetwarzania, aby poprawić Interaction to Next Paint!
W skrócie: Interaction to Next Paint (INP) mierzy, ile czasu zajmuje użytkownikowi zobaczenie zmiany wizualnej na stronie po interakcji z nią. INP można podzielić na 3 komponenty: 'opóźnienie wejścia', 'czas przetwarzania' i 'opóźnienie prezentacji'. Czas przetwarzania jest głównym czynnikiem wpływającym na całkowity INP, stanowiąc średnio około 40% opóźnienia. Oznacza to, że optymalizacja kodu JavaScript, w szczególności obsługi zdarzeń, może znacząco wpłynąć na wynik INP Twojej witryny.
WSKAZÓWKA INP: czas przetwarzania można zoptymalizować, natychmiast uruchamiając ważny kod poprzedzający aktualizację layoutu i planując wykonanie pozostałego kodu po niej.
Table of Contents!
Czym jest czas przetwarzania?

Interaction to Next Paint (INP) można podzielić na 3 części składowe: 'opóźnienie wejścia', 'czas przetwarzania' i 'opóźnienie prezentacji'
Czas przetwarzania odnosi się do czasu potrzebnego przeglądarce na wykonanie powiązanego callbacku zdarzenia po interakcji użytkownika ze stroną (np. kliknięcie przycisku lub naciśnięcie klawisza). Chociaż zawsze występuje pewien czas przetwarzania, problemy z INP pojawiają się, gdy callbacki zdarzeń zajmują zbyt dużo czasu przetwarzania.
Czas przetwarzania a INP
Czas przetwarzania może być 'tym elementem', o którym myślisz, optymalizując Interaction to Next Paint. To 'zadanie do wykonania' zanim przeglądarka będzie mogła zaktualizować layout.
Wielu programistów myśli o poprawie INP w kategoriach optymalizacji funkcji callback (optymalizacji czasu przetwarzania) i mają rację. Jednak pod względem ważności czas przetwarzania nie jest nawet najważniejszą częścią do poprawy, ale wciąż stanowi średnio około 40% całkowitego czasu INP.

W CoreDash zbieramy miliony punktów danych Core Web Vitals co godzinę. Na podstawie tych danych czas przetwarzania stanowi 40% Interaction to Next Paint. I chociaż to dużo, sama optymalizacja czasu przetwarzania najprawdopodobniej nie wystarczy do rozwiązania problemów z INP
Przykład czasu przetwarzania: Gdy użytkownik wchodzi w interakcję ze stroną, np. klika przycisk, czas potrzebny na zakończenie wykonania obsługi zdarzenia powiązanego z tym kliknięciem to czas przetwarzania. Na przykład, jeśli użytkownik kliknie przycisk, aby wysłać formularz, kod walidujący dane formularza, wysyłający je na serwer i obsługujący odpowiedź wpływa na czas przetwarzania. Im dłużej trwają te operacje, tym dłuższy czas przetwarzania i potencjalnie gorszy wynik INP.
Co powoduje wysoki czas przetwarzania?
Aby zacząć naprawiać problemy z INP spowodowane wysokim czasem przetwarzania, musimy zrozumieć, jakie mogą być możliwe przyczyny wysokiego czasu przetwarzania. Wysoki czas przetwarzania, czyli czas potrzebny na wykonanie callbacków zdarzeń, może być spowodowany niepotrzebnym kodem, niezoptymalizowanym kodem, nagromadzonymi callbackami i layout thrashing. Przyjrzyjmy się bliżej tym 4 obszarom.

- Niepotrzebny kod. Stary, nieużywany kod lub kod bez bezpośredniego znaczenia dla interakcji użytkownika może wydłużać czas wykonania callbacków.
- Niezoptymalizowany kod. Nieefektywny kod (zwykle pętle lub nieefektywne wyszukiwania w DOM) może powodować wolniejsze działanie callbacków zdarzeń niż to konieczne.
- Nagromadzone callbacki: Wiele callbacków zdarzeń zaplanowanych blisko siebie tworzy kolejkę. Jeśli callback wywołany interakcją użytkownika utknie w tej kolejce, odpowiedź wydaje się opóźniona.
- Layout thrashing: Częste manipulacje DOM, które wymuszają ponowne obliczanie layoutu, mogą obciążać przeglądarkę i prowadzić do regresji wydajności.
Minimalizacja czasu przetwarzania

Aby zminimalizować czas przetwarzania, musimy sprawić, by kod odpowiedzialny za późniejszą aktualizację layoutu działał jak najszybciej. Możemy to osiągnąć, optymalizując istniejący kod (usuwając niepotrzebny kod i optymalizując obecny) oraz rozróżniając między kodem, który musi się wykonać przed i po aktualizacji layoutu. Zasadniczo kod krytyczny dla aktualizacji layoutu musi się wykonać przed nią, a cały pozostały kod może się wykonać po aktualizacji layoutu.
- Usuń nieużywany kod. Chociaż usuwanie nieużywanego kodu może wydawać się oczywiste, na większości stron jest przynajmniej trochę starego, nieużywanego kodu, który po prostu się wykonuje, nie dodając niczego do strony ani UX. Oznacza to, że pierwszym krokiem jest upewnienie się, że żaden niepotrzebny kod się nie wykonuje. Można to zrobić na wiele sposobów. Na przykład przez proces zwany tree shaking lub code splitting. Lub ręcznie, sprawdzając pokrycie kodu w Chrome, a także używając dobrego IDE, które wskaże nieużywany kod. (Wskazówka: krytycznie przyjrzyj się również zasobom ładowanym przez Tag Manager)
- Minimalizuj czas wykonania callbacków: Użyj profilera JavaScript, aby zidentyfikować wąskie gardła w kodzie i skup się na tych obszarach do optymalizacji. Rozważ techniki takie jak memoizacja, wstępne obliczenia i buforowanie, aby uniknąć zbędnych obliczeń. (Wskazówka: możesz użyć panelu wydajności Chrome, aby znaleźć skrypty z długim czasem wykonania!)
- Priorytetyzuj krytyczny kod i planuj pozostały: Gdy kod callbacków został zoptymalizowany, podziel go na kod, który musi się wykonać natychmiast, i kod, który można odroczyć. Spójrz na ten przykład z życia wzięty:

W tym przykładzie callbacki Google Tag Manager i Facebook wykonują się przed kodem (REACT), który poprzedza aktualizację layoutu. Rozwiązaniem byłoby zaplanowanie callbacków GTM na czas bezczynności przeglądarki - Unikaj layout thrashing lub reflow. Layout thrashing występuje, gdy aktualizacje stylów i odczyty stylów są mieszane w pętli, powodując wielokrotne ponowne obliczanie layoutu przez przeglądarkę.
Aby uniknąć layout thrashing, wykonaj wszystkie zmiany stylów ("ustawienia") przed odczytywaniem wartości stylów ("odczyty"). Takie podejście minimalizuje częstotliwość aktualizacji layoutu, prowadząc do szybszej strony.
Na przykład, w pętli ustawiającej szerokość każdego akapitu na szerokość elementu, odczytaj szerokość elementu raz przed pętlą i użyj tej wartości do aktualizacji szerokości akapitów wewnątrz pętli.
Jak priorytetyzować krytyczny kod
Ostatni punkt 'Priorytetyzuj krytyczny kod i planuj pozostały' może być nieco abstrakcyjny dla wielu z Was. Możemy priorytetyzować krytyczny kod, używając requestIdleCallback() oraz yielding do głównego wątku.
Używamy requestIdleCallback dla mniej ważnych zadań, które nie muszą być wykonane natychmiast: Oto przykład przed i po planowania zdarzenia GTM.
/* before :: immediately run code */
gtag('event', '<event_name>', {
'event_category': '<event_category>',
});
/* after :: run the same code during browser idle */
requestIdleCallback(() => {
gtag('event', '<event_name>', {
'event_category': '<event_category>',
});
}, { timeout: 1000 });
Wadą requestIdleCallback jest to, że kod może nie wykonać się tak szybko, jak byśmy chcieli. W takim przypadku możemy 'oddać kontrolę głównemu wątkowi' po wykonaniu najważniejszego kodu, dając przeglądarce chwilę na wykonanie aktualizacji layoutu. Oto przykład, jak dzielić zadania przez yielding do głównego wątku
async function yieldToMain() {
if ('scheduler' in window && 'yield' in window.scheduler) {
return await window.scheduler.yield();
}
return new Promise((resolve) => {
setTimeout(resolve, 0);
});
}
async function handleClick(){
// do the most important layout updates here
await yieldToMain();
// do other tasks that need to run as asap after the layout update
}W przyszłości moglibyśmy zrobić znacznie więcej z window.scheduler niż tylko yielding do głównego wątku. Moglibyśmy również priorytetyzować zadania za pomocą scheduler API (zobacz Tabela wsparcia).
Scheduler API udostępnia funkcję postTask() do bardziej szczegółowego planowania zadań poprzez ustawianie priorytetów, co pomaga przeglądarce priorytetyzować pracę, aby zadania o niskim priorytecie oddawały kontrolę głównemu wątkowi.
Funkcja postTask() przyjmuje trzy ustawienia priorytetów: 'background' dla zadań o najniższym priorytecie, 'user-visible' dla zadań o średnim priorytecie i 'user-blocking' dla krytycznych zadań wymagających wysokiego priorytetu.
Priorytetyzując krytyczne zadania z 'user-blocking', programiści mogą zapewnić ich wykonanie z wyższym priorytetem, pozwalając przeglądarce obsługiwać interakcje użytkowników bardziej responsywnie. Scheduler API udostępnia funkcję postTask() do bardziej szczegółowego planowania zadań poprzez ustawianie priorytetów, co pomaga przeglądarce priorytetyzować pracę, aby zadania o niskim priorytecie oddawały kontrolę głównemu wątkowi.
Praktyczne zastosowania
Przejdźmy do najważniejszego pytania: 'Co to wszystko oznacza dla mojej strony'. Rozłóżmy to na WordPress i REACT i zobaczmy, jak można poprawić Interaction to Next Paint w kontekście czasu przetwarzania.
WordPress
WordPress oferuje bardzo ograniczoną kontrolę nad skryptami. Wiele skryptów jest dodawanych przez wtyczki. Najczęściej te skrypty dodają 'nasłuchiwacze zdarzeń' do strony, które nie robią nic poza opóźnianiem Interaction to Next Paint (INP). Jeśli Twoja strona WordPress ma problemy z Interaction to Next Paint spowodowane długim czasem przetwarzania, wykonaj następujące kroki:
- Sprawdź ustawienia motywu. Odznacz niepotrzebne opcje takie jak 'płynne przewijanie' lub 'animowane menu'. Takie ustawienia często powodują problemy z INP.
- Sprawdź, które skrypty są odpowiedzialne za długi czas przetwarzania (wskazówka: użyj panelu wydajności Chrome). Jeśli te skrypty są związane z wtyczkami, rozważ znalezienie innej wtyczki o podobnej funkcjonalności
- Często na stronie działają niestandardowe skrypty. Sprawdź te skrypty i upewnij się, że często oddają kontrolę głównemu wątkowi oraz zawijaj mniej ważne callbacki w funkcję requestIdleCallback
- Wyładuj nieużywane skrypty na poziomie poszczególnych stron (wskazówka: użyj wp_deregister_script). Niektóre wtyczki mają tendencję do wstrzykiwania skryptów na każdej stronie, nawet gdy funkcjonalność nie jest potrzebna.
- Sprawdź swój Tag Manager i usuń nieużywane lub niepotrzebne tagi.
- Używaj lekkich i czystych motywów. Często motywy uniwersalne, które 'robią wszystko', mają więcej skryptów
- Unikaj page builderów, ponieważ często w dużym stopniu polegają na JavaScript do prezentowania stron użytkownikowi końcowemu
REACT / NextJS
Hooki i funkcje Reacta umożliwiają redukcję czasu przetwarzania INP:
Priorytetyzuj interakcję użytkownika za pomocą funkcji współbieżności Reacta:
Funkcje współbieżności Reacta wprowadzone w wersjach 16 i 18 udostępniają hooki i mechanizmy optymalizacji renderowania dla płynniejszego UX, szczególnie podczas wprowadzania danych.
useTransitionistartTransition: Oznacz niekrytyczne aktualizacje do późniejszego renderowania. Zapobiega to blokowaniu interakcji użytkownika przez duże aktualizacje.useDeferredValue: Podziel interfejs na sekcje istotne i mniej krytyczne. React może przerwać renderowanie mniej krytycznych części dla bardziej responsywnego doświadczenia.useOptimistic: Pokaż tymczasowy, optymistyczny stan podczas trwania operacji asynchronicznych (np. żądań sieciowych). Utrzymuje to responsywność interfejsu nawet podczas pobierania danych.
Suspense do pobierania danych (React 18+):
Suspense w React 18 może być używany do poprawy INP (Interaction to Next Paint), pozwalając przeglądarce priorytetyzować interakcje użytkowników i optymalizować renderowanie. Podczas gdy React 16 wprowadził Suspense do code splitting, React 18 rozszerza tę funkcjonalność na pobieranie danych.
- Komponent fallback, taki jak wskaźnik ładowania, wyświetla się podczas ładowania danych.
- Gdy dane dotrą, React wznawia renderowanie zawieszonego komponentu.
- Suspense, w połączeniu z przerywalnym renderowaniem w Concurrent React, priorytetyzuje interakcje użytkowników. Jeśli użytkownik wchodzi w interakcję z zawieszonym komponentem, React priorytetyzuje renderowanie tego komponentu, utrzymując responsywność.
Ogólnie, te funkcje współpracują ze sobą, aby React priorytetyzował interakcje użytkowników i unikał blokowania interfejsu podczas aktualizacji lub pobierania danych.
Lab data is not enough.
I analyze your field data to find the edge cases failing your user experience.
- Real User Data
- Edge Case Detection
- UX Focused

