INP, czyli Interaction to Next Paint. Wskazuje na to, jak szybko frontend strony odpowiada po dokonaniu na niej jakiejś interakcji.

Wyobraź sobie, że klikasz w jakiś element (np. link), kursor myszy jest "zamrożony", a Ty wręcz czujesz, że strona "wisi" i nie odpowiada. Nic nie pojawia się na ekranie, nie wiadomo co się dzieje.

O takich przypadkach nieresponsywności (lub inaczej - słabego poziomu responsywności) traktuje metryka INP.

Interakcje, które mierzy ta metryka to:
- kliknięcie w jakiś element
- interakcja "tap" (na ekranach dotykowych)
- wpisywanie jakiegoś tekstu w inputach

INP nie bierze pod uwagę scrollowania, czy też jak szybko pojawia się efekt :hover po najechaniu na jakiś element kursorem myszy. 

O tym, jak mierzyć INP na stronie w łatwy sposób, korzystając z biblioteki web-vitals, mówiłem na moim ostatnim webinarze o wydajnym frontendzie w 2023 (zobacz od 49:48).

Dziś pokażę Ci ciekawy przykład, który specjalnie stworzyłem na potrzeby tego artykułu.

Demo #1: https://frontend-perf-tests.vercel.app/inp-tests/test-a.html
Na tej stronie znajduje się link wyzwalający kosztowną operację JS, która konsumuje sporo CPU Twojego urządzenia (tutaj na GitHubie jest kod, którym się posłużyłem).

Jeżeli otworzysz narzędzie DevTools -> Performance, włączysz nagrywanie i klikniesz w link na stronie, powstanie rezultat w postaci osi czasu, na której zobaczysz, co się dzieje w głównym wątku Twojej przeglądarki (należy zwrócić uwagę w sekcji Interactions na żółty event o nazwie click):

Zrzut ekranu z narzędzia DevTools Performance prezentujący zablokowany główny wątek poprzez wykonanie interakcji kliknięcia na stronie

Zauważysz, że główny wątek został zablokowany na ponad 1s.
Dodatkowo biblioteka web-vitals zwróci pełne informacje na temat INP:

Przykład informacji o INP z biblioteki web-vitals

A teraz zobacz dalej.

Demo #2: https://frontend-perf-tests.vercel.app/inp-tests/test-b.html

Ta sama strona, ten sam wolny skrypt JS, ale z różnicą taką, że tuż po kliknięciu pojawia się warstwa z napisem "Loading", wskazując na ładowanie/wykonywanie się jakiejś operacji. Tuż po jej zakończeniu, warstwa ta znika. Czyli tuż po kliknięciu jak najszybciej prezentujemy użytkownikowi, że "coś się dzieje".

Sama zaś zasobożerna operacja jest wykonywana po jej uprzednim zaplanowaniu przez przeglądarkę, dzięki użyciu metody setTimeout().

Kod JS ukazujący przykład optymalizacji metryki INP

Jeżeli teraz dokonamy pomiaru wartości metryki INP, rezultat będzie następujący:

Rezultat pomiaru INP dzięki bibliotece web-vitals po optymalizacji

Rating: good :-) 

Jeżeli dokonamy nagrywania tej interakcji przez DevTools Performance, rezultat będzie następujący:

Zrzut z narzędzia DevTools Performance pokazujący interakcję i dużo lepszy rezultat w postaci mniej zablokowanego głównego wątku podczas interakcji kliknięcia w element na stronie

Co się zmieniło:
- w sekcji Interactions, sama interakcja click jest dużo krótsza, gdyż zajmuje znacznie mniej czasu
- wykonanie zasobożernego kodu jest zaplanowane (Timer Fired) i nie przeciąga eventu click

Kod nadal blokuje główny wątek przeglądarki na ponad 1s. (tutaj nic się nie zmieniło, wszak nie zmieniliśmy kodu, który jest obciążający, a jedynie pozwoliliśmy przeglądarce lepiej zaplanować jego wykonanie, priorytetyzując przedstawienie użytkownikowi informacji o ładowaniu.

No dobra, a co z samym wykorzystującym nadmiarowo CPU kodem i jego optymalizacją? W tym konkretnym przypadku idealnie byłoby wykonać go na innym wątku przeglądarki, wykorzystując web worker. Rezultat tej operacji (obliczenia) nie potrzebuje w żaden sposób modyfikować struktury DOM, więc takie rozwiązanie wydaje się być idealnym wyjściem.

Inne aspekty, jakie należy wziąć pod uwagę podczas wykonywania jakiejś operacji po interakcji, to np. czy dany kod JS nie wykonuje jakiejś rekalkulacji styli (która może afektować setki albo nawet i tysiące node'ów dokumentu HTML), zwłaszcza, gdy po niej może dochodzić np. do fazy layout, aby coś wyrenderować na nowo.

Polecam również to rozszerzenie do przeglądarki Chrome, dzięki któremu łatwiej będzie Ci zauważyć rezultat metryki INP na stronach.

Jeżeli chcesz poznać pełny proces optymalizacji interakcji na frontendzie, zachęcam Cię do dołączenia do kursu Wydajne Interakcje na Frontendzie 2024. Cena w przedsprzedaży to jedynie 499 PLN + VAT lub w pakiecie z kursem Zoptymalizowany Frontend za 1897 PLN + VAT. Oferta ważna tylko do 31. października 2023.