Dowiedz się, czym jest opóźnienie wejściowe, i poznaj techniki, które pozwolą je zmniejszyć, aby przyspieszyć interakcję.
Interakcje w internecie są złożone, a w przeglądarce zachodzi wiele różnych działań, 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 wywołań 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 progowej „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 danych wejściowych, 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ą wejść w interakcję ze stroną, 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 można uniknąć. Jeśli masz problemy z długimi opóźnieniami we wprowadzaniu danych, weź pod uwagę te kwestie.
Unikaj powtarzających się timerów, 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 uruchamiane 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ć pomocne w unikaniu długich zadań. Zależy to jednak od tego, kiedy wystąpi przekroczenie limitu czasu i czy użytkownik spróbuje wejść w interakcję ze stroną, gdy zostanie wywołane wywołanie zwrotne przekroczenia 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ć następnej iteracji, dopóki nie zakończy się poprzednia. Oznacza to, że pętla będzie za każdym razem przekazywać kontrolę do wątku głównego, gdy zostanie wywołana funkcja setTimeout. Należy jednak zadbać o to, aby funkcja zwrotna nie wykonywała 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 wejściowego, jak pokazano na panelu wydajności w Narzędziach deweloperskich w Chrome. Dodane opóźnienie wejścia 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 czasu 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 działania, 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 dane wejściowe użytkownika, dzieląc długie zadania.
Zwróć uwagę na nakładanie się interakcji
Szczególnie trudnym aspektem optymalizacji INP może być sytuacja, w której masz 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 pierwsza interakcja zdąży wyrenderować następną klatkę.
Źródła nakładania się interakcji mogą być proste, np. użytkownicy wykonują wiele interakcji 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 do backendu wysyłane są żądania sieciowe, masz kilka opcji:
- Rozważ eliminację drgań klawiszy 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. W szczególności animacje w JavaScript mogą wywoływać 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 danych wejściowych, 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 we wprowadzaniu danych, co przełoży się na szybsze interakcje użytkowników z Twoją witryną.
Baner powitalny z Unsplash, autor: Erik Mclean.