Dowiedz się, czym jest opóźnienie danych wejściowych, i poznaj techniki jego zmniejszania, aby przyspieszyć interaktywność.
Interakcje w internecie są skomplikowane, ponieważ w przeglądarce zachodzą różne rodzaje aktywności, które je napędzają. Wszystkie te elementy mają jednak wspólną cechę: powodują pewne opóźnienie wejściowe, zanim zaczną działać wywołania zwrotne zdarzeń. Z tego przewodnika dowiesz się, czym jest opóźnienie wejściowe i co możesz zrobić, aby je zminimalizować i przyspieszyć interakcje w witrynie.
Czym jest opóźnienie wejściowe?
Opóźnienie przy działaniu to okres od pierwszej interakcji użytkownika ze stroną (np. kliknięcia ekranu, kliknięcia myszą lub naciśnięcia klawisza) do momentu, gdy zaczynają działać wywołania zwrotne zdarzenia związane z interakcją. Każda interakcja zaczyna się od pewnego opóźnienia danych wejściowych.
Pewna część opóźnienia wejściowego jest nieunikniona: system operacyjny zawsze potrzebuje trochę czasu na rozpoznanie zdarzenia wejściowego i przekazanie go do przeglądarki. Jednak ta część opóźnienia wejściowego jest często niezauważalna, a na samej stronie dzieją się inne rzeczy, które mogą wydłużyć opóźnienia wejściowe na tyle, że spowodują problemy.
Jak interpretować opóźnienie wejściowe
Ogólnie rzecz biorąc, każda część interakcji powinna być jak najkrótsza, aby witryna miała jak największe szanse na osiągnięcie „dobrego” progu wskaźnika interakcji do kolejnego wyrenderowania (INP), niezależnie od urządzenia użytkownika. Utrzymanie opóźnienia wejściowego pod kontrolą to tylko jeden z elementów, które pozwalają osiągnąć ten próg.
Dlatego, aby osiągnąć „dobry” próg INP, należy dążyć do jak najkrótszego opóźnienia wejściowego. Pamiętaj jednak, że nie da się całkowicie wyeliminować opóźnień wejściowych. Jeśli unikasz nadmiernego obciążenia wątku głównego, gdy użytkownicy próbują wejść w interakcję ze stroną, opóźnienie przy wprowadzaniu powinno być na tyle niskie, aby nie powodowało problemów.
Jak zminimalizować opóźnienie wejściowe
Jak już wspomnieliśmy, pewnego opóźnienia wejściowego nie da się uniknąć, ale z drugiej strony niektóre opóźnienia wejściowe można wyeliminować. Jeśli masz problemy z długimi opóźnieniami, weź pod uwagę te kwestie.
Unikaj powtarzających się timerów, które powodują nadmierne obciążenie wątku głównego.
W JavaScripcie są 2 często używane funkcje licznika czasu, które mogą przyczyniać się do opóźnienia przy wejściu: setTimeout i setInterval. Różnica między nimi polega na tym, że setTimeout planuje uruchomienie wywołania zwrotnego po określonym czasie. Z kolei setInterval planuje wywołanie zwrotne, które będzie uruchamiane co n milisekund bezterminowo lub do momentu zatrzymania licznika za pomocą clearInterval.
setTimeout nie jest problematyczne samo w sobie – może być pomocne w unikaniu długich zadań. Zależy to jednak od tego, kiedy nastąpi przekroczenie limitu czasu i czy użytkownik spróbuje wejść w interakcję ze stroną, gdy zostanie uruchomione wywołanie zwrotne po przekroczeniu limitu czasu.
Dodatkowo setTimeout można uruchamiać w pętli lub rekurencyjnie, co działa podobnie do setInterval, ale najlepiej nie planować kolejnej iteracji, dopóki nie zakończy się poprzednia. Oznacza to, że pętla będzie przekazywać sterowanie do wątku głównego za każdym razem, gdy wywoływana jest funkcja setTimeout, ale musisz zadbać o to, aby jej wywołanie zwrotne nie wykonywało zbyt wielu zadań.
setInterval uruchamia wywołanie zwrotne w interwale, dlatego jest znacznie bardziej prawdopodobne, że będzie przeszkadzać w interakcjach. Dzieje się tak, ponieważ – w przeciwieństwie do pojedynczego wywołania setTimeout, które jest jednorazowym wywołaniem zwrotnym, które może zakłócić interakcję użytkownika – cykliczny charakter setInterval sprawia, że będzie ono zakłócać interakcję, co zwiększy opóźnienie interakcji.
setInterval, który przyczynia się do opóźnienia wejściowego, jak pokazano w panelu wydajności Narzędzi deweloperskich w Chrome. Dodatkowe opóźnienie danych wejściowych powoduje, że wywołania zwrotne zdarzeń interakcji są uruchamiane później, niż mogłyby być.
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ć ich działanie. Inaczej jest jednak w przypadku liczników czasu w skryptach innych firm. Często nie masz kontroli nad tym, co robi skrypt innej firmy, a rozwiązanie problemów z wydajnością w kodzie innej firmy często wymaga współpracy z interesariuszami w celu ustalenia, czy dany skrypt innej firmy jest konieczny. Jeśli tak, musisz skontaktować się z dostawcą skryptu, aby ustalić, co można zrobić, aby rozwiązać problemy z wydajnością, które może on powodować w Twojej witrynie.
Unikaj długich zadań
Jednym ze sposobów na ograniczenie długich opóźnień wejściowych jest unikanie długich zadań. Jeśli wątek główny jest nadmiernie obciążony i blokowany podczas interakcji, opóźnienie działania będzie się zwiększać, zanim długie zadania zostaną ukończone.
Oprócz minimalizowania ilości pracy wykonywanej w ramach zadania (zawsze staraj się wykonywać jak najmniej pracy w głównym wątku) możesz poprawić czas reakcji na dane wejściowe użytkownika, dzieląc długie zadania.
Zwracaj uwagę na nakładanie się interakcji
Szczególnie trudnym elementem optymalizacji INP mogą być nakładające się interakcje. Nakładanie się interakcji oznacza, że po wejściu w interakcję z jednym elementem wykonujesz kolejną interakcję ze stroną, zanim początkowa interakcja zdąży wyrenderować następną klatkę.
Źródłem nakładania się interakcji może być po prostu to, że użytkownicy wykonują wiele interakcji w krótkim czasie. Może się to zdarzyć, gdy użytkownicy wpisują tekst w polach formularza, gdzie w bardzo krótkim czasie może wystąpić wiele interakcji z klawiaturą. Jeśli praca nad kluczowym zdarzeniem jest szczególnie kosztowna – jak w częstym przypadku pól autouzupełniania, w których żądania sieciowe są wysyłane do backendu – masz kilka opcji:
- Rozważ eliminację drgań danych wejściowych, aby ograniczyć liczbę wywołań zwrotnych zdarzenia w danym okresie.
- Użyj
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 przerywania zdarzeń.
Innym źródłem zwiększonego opóźnienia wejściowego z powodu nakładających się interakcji mogą być kosztowne animacje. W szczególności animacje w języku JavaScript mogą wywoływać wiele wywołań requestAnimationFrame, co może utrudniać interakcje użytkownika. Aby tego uniknąć, używaj animacji CSS, gdy tylko jest to możliwe, aby uniknąć kolejkowania potencjalnie kosztownych klatek animacji. Jeśli jednak to zrobisz, unikaj nieskomponowanych animacji, aby animacje były uruchamiane głównie w wątkach GPU i kompozytora, a nie w głównym wątku.
Podsumowanie
Opóźnienia wejściowe 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 wejściowe, możesz je zmniejszyć. Unikanie cyklicznych wywołań zwrotnych, dzielenie długich zadań i świadomość potencjalnego nakładania się interakcji mogą pomóc w zmniejszeniu opóźnienia przy wejściu, co przyspieszy interaktywność witryny dla użytkowników.