Dowiedz się, czym jest opóźnienie wejścia, i poznaj techniki, które pozwolą je zmniejszyć, aby przyspieszyć interakcję.
Interakcje w internecie są złożone, a w przeglądarce zachodzą różne działania, które je wywołują. Wszystkie te zdarzenia łączy jednak to, że przed uruchomieniem wywołań zwrotnych zdarzeń występuje pewne opóźnienie wejściowe. Z tego przewodnika dowiesz się, czym jest opóźnienie wejściowe i co możesz zrobić, aby je zminimalizować i przyspieszyć interakcje w swojej witrynie.
Czym jest opóźnienie wejściowe?
Opóźnienie przy pierwszym działaniu to czas, jaki upływa od pierwszej interakcji użytkownika ze stroną (np. kliknięcia ekranu, kliknięcia myszą lub naciśnięcia klawisza) do momentu rozpoczęcia wykonywania funkcji zwrotnych zdarzenia. Każda interakcja zaczyna się od pewnego opóźnienia.
Część opóźnienia wejściowego jest nieunikniona: system operacyjny zawsze potrzebuje trochę czasu, aby rozpoznać zdarzenie wejściowe i przekazać je do przeglądarki. Ta część opóźnienia wejściowego jest jednak często niezauważalna, a na samej stronie zachodzą inne procesy, które mogą powodować opóźnienia wejściowe na tyle długie, że stają się problemem.
Jak rozumieć opóźnienie wejściowe
Ogólnie rzecz biorąc, warto skrócić każdą część interakcji do minimum, aby witryna miała jak największe szanse na osiągnięcie wartości „dobrej” wskaźnika interakcji do kolejnego wyrenderowania (INP) niezależnie od urządzenia użytkownika. Kontrolowanie opóźnienia wejściowego to tylko jeden z elementów spełnienia tego progu.
Dlatego warto dążyć do jak najkrótszego opóźnienia wejściowego, aby osiągnąć próg „dobry” w przypadku INP. Pamiętaj jednak, że nie możesz całkowicie wyeliminować opóźnień we wprowadzaniu danych. Jeśli unikasz nadmiernego obciążenia wątku głównego, gdy użytkownicy próbują korzystać z Twojej strony, opóźnienie danych wejściowych powinno być wystarczająco małe, aby nie powodować problemów.
Jak zminimalizować opóźnienie wejściowe
Jak już wspomnieliśmy, pewne opóźnienie wejściowe jest nieuniknione, ale z drugiej strony pewne opóźnienie wejściowe jest do uniknięcia. Jeśli masz problemy z długimi opóźnieniami w reagowaniu na dane wejściowe, weź pod uwagę te kwestie.
Unikaj powtarzających się liczników czasu, które powodują nadmierne obciążenie wątku głównego.
W JavaScript są 2 często używane funkcje czasowe, które mogą przyczyniać się do opóźnienia danych wejściowych: setTimeout i setInterval. Różnica między nimi polega na tym, że funkcja setTimeout planuje wywołanie zwrotne po upływie określonego czasu. setInterval z kolei planuje wywołanie zwrotne, które będzie wykonywane co n milisekund w nieskończoność lub do momentu zatrzymania timera za pomocą funkcji clearInterval.
setTimeout nie jest samo w sobie problematyczne – w rzeczywistości może być przydatne w unikaniu długich zadań. Zależy to jednak od tego, kiedy wystąpi limit czasu i czy użytkownik spróbuje wejść w interakcję ze stroną, gdy zostanie wywołane wywołanie zwrotne limitu czasu.
Dodatkowo funkcję setTimeout można uruchamiać w pętli lub rekurencyjnie, w którym to przypadku działa bardziej jak funkcja setInterval, ale najlepiej nie planować kolejnej iteracji, dopóki poprzednia się nie zakończy. Oznacza to, że pętla będzie za każdym razem ustępować miejsca głównemu wątkowi, gdy zostanie wywołana funkcja setTimeout. Należy jednak zadbać o to, aby wywołanie zwrotne nie wykonywało zbyt wielu czynności.
setInterval wywołuje funkcję zwrotną w określonych odstępach czasu, dlatego znacznie częściej utrudnia interakcje. Dzieje się tak, ponieważ w przeciwieństwie do pojedynczego wywołania funkcji setTimeout, które jest jednorazowym wywołaniem zwrotnym i może utrudniać interakcję użytkownika, powtarzający się charakter funkcji setInterval sprawia, że prawdopodobnie będzie ona utrudniać interakcję, a tym samym zwiększać opóźnienie wejściowe interakcji.
setInterval, który przyczynia się do opóźnienia danych wejściowych, jak pokazano w panelu wydajności Narzędzi deweloperskich w Chrome. Dodane opóźnienie danych wejściowych powoduje, że wywołania zwrotne zdarzeń dla interakcji są wykonywane później niż w innych przypadkach.
Jeśli liczniki czasu występują w kodzie własnym, masz nad nimi kontrolę. Zastanów się, czy są Ci potrzebne, lub postaraj się jak najbardziej ograniczyć w nich pracę. Jednak liczniki w skryptach innych firm to zupełnie inna sprawa. Często nie masz kontroli nad tym, co robi skrypt firmy zewnętrznej. Rozwiązywanie problemów z wydajnością w kodzie firmy zewnętrznej często wymaga współpracy z zainteresowanymi stronami w celu ustalenia, czy dany skrypt firmy zewnętrznej jest niezbędny. Jeśli tak, skontaktuj się z dostawcą skryptu firmy zewnętrznej, aby ustalić, co można zrobić, aby rozwiązać problemy z wydajnością, które mogą występować w Twojej witrynie.
Unikaj długich zadań
Jednym ze sposobów na ograniczenie długich opóźnień w reakcji na dane wejściowe jest unikanie długich zadań. Jeśli masz nadmierną ilość pracy w wątku głównym, która blokuje go podczas interakcji, zwiększy to opóźnienie wejścia, zanim długie zadania zdążą się zakończyć.
Oprócz minimalizowania ilości pracy wykonywanej w ramach zadania – a w wątku głównym zawsze należy dążyć do wykonywania jak najmniejszej ilości pracy – możesz poprawić szybkość reakcji na działania użytkownika, dzieląc długie zadania.
Zwracaj uwagę na nakładanie się interakcji
Szczególnie trudnym aspektem optymalizacji INP może być nakładanie się interakcji. Nakładanie się interakcji oznacza, że po wejściu w interakcję z jednym elementem wykonujesz kolejną interakcję ze stroną, zanim pierwsza interakcja zdąży wyrenderować następną klatkę.
Źródła nakładania się interakcji mogą być tak proste, jak wiele interakcji użytkowników w krótkim czasie. Może się to zdarzyć, gdy użytkownicy wpisują tekst w polach formularza, w których w bardzo krótkim czasie może wystąpić wiele interakcji z klawiaturą. Jeśli praca nad kluczowym zdarzeniem jest szczególnie kosztowna, np. w przypadku pól autouzupełniania, w których wysyłane są żądania sieciowe do backendu, masz kilka opcji:
- Rozważ odrzucanie danych wejściowych, aby ograniczyć liczbę wywołań zwrotnych zdarzeń w danym okresie.
- Używaj
AbortController, aby anulować wychodzące żądaniafetch, dzięki czemu wątek główny nie będzie przeciążony obsługą wywołań zwrotnychfetch. Uwaga: właściwośćsignalinstancjiAbortControllermoże też służyć do prerywania zdarzeń.
Innym źródłem zwiększonego opóźnienia we wprowadzaniu danych z powodu nakładających się interakcji mogą być kosztowne animacje. Animacje w JavaScript mogą generować wiele wywołań requestAnimationFrame, co może utrudniać interakcje użytkowników. Aby tego uniknąć, w miarę możliwości używaj animacji CSS, aby uniknąć kolejkowania potencjalnie kosztownych klatek animacji. Jeśli to zrobisz, unikaj nieskomponowanych animacji, aby animacje działały głównie na wątkach GPU i kompozytora, a nie na wątku głównym.
Podsumowanie
Opóźnienia we wprowadzaniu danych mogą nie stanowić większości czasu potrzebnego na wykonanie interakcji, ale warto pamiętać, że każda część interakcji zajmuje pewien czas, który można skrócić. Jeśli obserwujesz długie opóźnienie we wprowadzaniu danych, możesz je skrócić. Unikanie powtarzających się wywołań zwrotnych timera, dzielenie długich zadań i świadomość potencjalnego nakładania się interakcji mogą pomóc w zmniejszeniu opóźnienia wejściowego, co przełoży się na szybsze interakcje dla użytkowników Twojej witryny.
Baner powitalny z Unsplash, autor: Erik Mclean.