Renderowanie kodu HTML i interaktywności po stronie klienta

Renderowanie kodu HTML za pomocą JavaScriptu różni się od renderowania kodu HTML wysyłanego przez serwer i może mieć wpływ na wydajność. Z tego przewodnika dowiesz się, na czym polega różnica i jak możesz poprawić wydajność renderowania witryny, zwłaszcza w przypadku interakcji.

Analiza i renderowanie kodu HTML jest w przypadku witryn korzystających z wbudowanej funkcji nawigacji wbudowanej w przeglądarkach, co jest często nazywane „tradycyjnym wczytywaniem stron”. lub „trudna nawigacja”. Takie witryny są czasami nazywane aplikacjami wielostronicowymi (MPA).

Programiści mogą jednak obejść ustawienia domyślne przeglądarki, aby dostosować je do swoich potrzeb. Dotyczy to oczywiście witryn korzystających ze wzorca aplikacji jednostronicowej (SPA), który dynamicznie tworzy w kliencie dużą część HTML/DOM za pomocą JavaScriptu. Nazwa tego wzorca projektu pochodzi od renderowania po stronie klienta. Jeśli ilość nakładu pracy jest zbyt duża, może to mieć wpływ na interakcję z następnym wyrenderowaniem (INP) witryny.

Ten przewodnik pomoże Ci ocenić różnicę między używaniem kodu HTML wysyłanego przez serwer do przeglądarki a tworzeniem go w kliencie za pomocą JavaScriptu oraz jak to drugie może spowodować duże opóźnienia interakcji w kluczowych momentach.

Jak przeglądarka renderuje kod HTML dostarczony przez serwer

Wzorzec nawigacji używany podczas tradycyjnego ładowania strony obejmuje odbieranie kodu HTML z serwera przy każdej nawigacji. Jeśli wpiszesz adres URL w pasku adresu przeglądarki lub klikniesz link w pliku MPA, zajdzie ta seria zdarzeń:

  1. Przeglądarka wysyła żądanie nawigacji dla podanego adresu URL.
  2. Serwer odpowiada fragmentem HTML.

Ostatni krok jest kluczowy. To także jedna z najważniejszych optymalizacji wydajności w ramach wymiany serwer-przeglądarka, nazywana strumieniowaniem. Jeśli serwer może jak najszybciej rozpocząć wysyłanie kodu HTML, a przeglądarka nie czeka na pełną odpowiedź, może przetwarzać kod HTML we fragmentach.

Zrzut ekranu analizy kodu HTML wysłanego przez serwer przedstawiony w panelu wydajności w Narzędziach deweloperskich w Chrome. W miarę napływu kodu HTML jego fragmenty są przetwarzane w ramach kilku krótszych zadań, a renderowanie odbywa się przyrostowo.
Analiza i renderowanie kodu HTML dostarczonego przez serwer zgodnie z wizualizacją w panelu wydajności w Narzędziach deweloperskich w Chrome. Zadania związane z analizowaniem i renderowaniem kodu HTML są dzielone na fragmenty.

Podobnie jak w przypadku większości działań w przeglądarce, analiza kodu HTML ma miejsce w ramach zadań. Podczas przesyłania strumienia HTML z serwera do przeglądarki przeglądarka optymalizuje analizowanie tego kodu, robiąc to krok po kroku, w miarę jak fragmenty strumienia napływają we fragmentach. Skutkiem jest to, że po przetworzeniu każdego fragmentu przeglądarka okresowo poddaje się wątkiowi głównemu, co pozwala uniknąć długich zadań. Oznacza to, że w trakcie analizy kodu HTML mogą występować inne procesy, w tym prace związane z renderowaniem przyrostowym niezbędne do zaprezentowania strony użytkownikowi, a także przetwarzanie interakcji użytkownika, które mogą wystąpić w kluczowym okresie uruchamiania strony. Takie podejście przekłada się na lepszy wynik interakcji do kolejnego wyrenderowania (INP) dla strony.

Jakie wnioski? Jeśli przesyłasz strumieniowo kod HTML z serwera, uzyskujesz przyrostową analizę i renderowanie kodu HTML oraz automatyczne wyświetlanie w wątku głównym. Nie tak jest w przypadku renderowania po stronie klienta.

Jak przeglądarka renderuje kod HTML dostarczony przez JavaScript

Chociaż każde żądanie nawigacji na stronie wymaga dostarczenia przez serwer pewnej ilości kodu HTML, niektóre witryny używają wzorca SPA. Takie podejście często zakłada minimalny początkowy ładunek kodu HTML dostarczanego przez serwer. Potem klient wypełnia główny obszar treści strony kodem HTML wygenerowanym na podstawie danych pobranych z serwera. Kolejne nawigacji – czasami nazywane „rozkładaną nawigacją”. w tym przypadku są obsługiwane w całości przez JavaScript, aby dodać na stronie nowy kod HTML.

Renderowanie po stronie klienta może też występować w bardziej ograniczonych przypadkach w przypadku aplikacji innych niż SPA, gdy kod HTML jest dynamicznie dodawany do DOM przez JavaScript.

Istnieje kilka typowych sposobów tworzenia kodu HTML lub dodawania do modelu DOM za pomocą JavaScriptu:

  1. Właściwość innerHTML umożliwia określenie treści istniejącego elementu za pomocą ciągu znaków, który przeglądarka analizuje w DOM.
  2. Metoda document.createElement pozwala tworzyć nowe elementy dodawane do modelu DOM bez użycia analizy HTML przeglądarki.
  3. Metoda document.write umożliwia wpisanie kodu HTML w dokumencie (przeglądarka analizuje go tak samo, jak w metodzie nr 1). Z kilku powodów zdecydowanie odradzamy jednak korzystanie z document.write.
Zrzut ekranu przedstawiający analizę kodu HTML wyrenderowanego za pomocą JavaScriptu w panelu wydajności w Narzędziach deweloperskich w Chrome. Ta praca jest wykonywana w ramach jednego, długiego zadania, które blokuje wątek główny.
Analiza i renderowanie kodu HTML za pomocą JavaScriptu na kliencie, jak pokazano w panelu wydajności w Narzędziach deweloperskich w Chrome. Zadania związane z analizą i renderowaniem nie są podzielone na fragmenty, co skutkuje długim zadaniem, które blokuje wątek główny.

Konsekwencje tworzenia kodu HTML/DOM za pomocą JavaScriptu po stronie klienta mogą być znaczące:

  • W przeciwieństwie do kodu HTML przesyłanego przez serwer w odpowiedzi na żądanie nawigacji zadania JavaScript na kliencie nie są automatycznie dzielone na fragmenty, co może powodować długie zadania blokujące wątek główny. Oznacza to, że tworzenie zbyt dużej ilości kodu HTML/DOM jednocześnie na kliencie może negatywnie wpływać na wartość INP strony.
  • Jeśli podczas uruchamiania klient zostanie utworzony w kliencie kod HTML, zasoby, do których się on odwołuje, nie zostaną wykryte przez skaner wstępnego wczytywania przeglądarki. Z pewnością będzie to miało negatywny wpływ na największe wyrenderowanie treści (LCP) strony. Chociaż nie jest to problem z wydajnością w czasie działania (a nie jest to kwestia opóźnienia sieci podczas pobierania ważnych zasobów), ale nie chcesz mieć wpływu na LCP witryny przez pominięcie tej podstawowej optymalizacji pod kątem wydajności przeglądarki.

Co możesz zrobić, aby zwiększyć skuteczność renderowania po stronie klienta

Jeśli Twoja witryna w dużym stopniu opiera się na renderowaniu po stronie klienta i w danych pól zaobserwowano słabe wartości INP, możesz się zastanawiać, czy ma to związek z tym problemem. Jeśli na przykład witryna to SPA, dane z terenu mogą ujawnić interakcje odpowiedzialne za znaczną pracę związaną z renderowaniem.

Niezależnie od przyczyny poniżej znajdziesz kilka potencjalnych przyczyn, które możesz zbadać, aby rozwiązać problem.

Podaj jak najwięcej kodu HTML z serwera

Jak już wspomnieliśmy, przeglądarka domyślnie obsługuje kod HTML z serwera w bardzo wydajny sposób. Rozdziała analizowanie i renderowanie kodu HTML w sposób, który pozwala uniknąć długich zadań, i optymalizuje łączny czas trwania wątku głównego. Prowadzi to do obniżenia całkowitego czasu blokowania (TBT), a TBT jest silnie skorelowany z INP.

Przy tworzeniu witryny możesz wykorzystywać platformę frontendową. Jeśli tak, upewnij się, że renderujesz kod HTML komponentu na serwerze. Ograniczy to ilość potrzebnego na początku renderowania po stronie klienta, co powinno poprawić wrażenia użytkowników.

  • W przypadku React kod HTML na serwerze należy renderować za pomocą interfejsu Server DOM API. Pamiętaj jednak, że tradycyjna metoda renderowania po stronie serwera wykorzystuje podejście synchroniczne, co może prowadzić do wydłużenia czasu do pierwszego bajtu (TTFB), a także do zbierania kolejnych wskaźników, takich jak Pierwsze wyrenderowanie treści (FCP) czy LCP. Jeśli to możliwe, używaj interfejsów API strumieniowania dla Node.js lub innych środowisk wykonawczych JavaScript, aby serwer mógł jak najszybciej rozpocząć strumieniowe przesyłanie kodu HTML do przeglądarki. Next.js – platforma oparta na React – domyślnie udostępnia wiele sprawdzonych metod. Oprócz automatycznego renderowania kodu HTML na serwerze może on również statycznie generować kod HTML dla stron, które nie zmieniają się w zależności od kontekstu użytkownika (np. uwierzytelniania).
  • Vue domyślnie wykonuje też renderowanie po stronie klienta. Podobnie jak React, Vue może też renderować kod HTML komponentu na serwerze. W miarę możliwości korzystaj z tych interfejsów API po stronie serwera lub rozważ ogólną abstrakcję w projekcie Vue, aby ułatwić wdrożenie sprawdzonych metod.
  • Standardowo renderuje kod HTML na serwerze, ale jeśli kod komponentu wymaga dostępu do przestrzeni nazw tylko dla przeglądarki (np. window), możesz nie być w stanie wyrenderować kodu HTML tego komponentu na serwerze. W miarę możliwości wypróbuj alternatywne rozwiązania, aby nie powodować niepotrzebnego renderowania po stronie klienta. SvelteKit, który według Svelte jako Next.js to React, umieszcza w swoich projektach jak najwięcej sprawdzonych metod, dzięki czemu unikasz potencjalnych pułapek w projektach, w których jest ona używana samodzielnie.

Ogranicz liczbę węzłów DOM tworzonych na kliencie

Kiedy DOM jest duży, ilość przetwarzania niezbędnego do ich renderowania zazwyczaj wzrasta. Niezależnie od tego, czy Twoja witryna to pełnoprawna platforma SPA, czy też wstrzykujesz nowe węzły do istniejącego DOM w wyniku interakcji z MPA, staraj się, by te elementy DOM były jak najmniejsze. Zmniejszy to ilość pracy wymaganej podczas renderowania po stronie klienta przy wyświetlaniu tego kodu HTML i pozwoli utrzymać niższy współczynnik INP witryny.

Zastanów się nad architekturą instancji roboczych usługi strumieniowania

To zaawansowana technika, która nie zawsze sprawdza się w każdym przypadku użycia, ale umożliwia przekształcenie MPA w witrynę, która błyskawicznie się wczytuje, gdy użytkownicy przechodzą z jednej strony na następną. Skrypt service worker pozwala wstępnie buforować statyczne części witryny w CacheStorage, a interfejs API ReadableStream pobiera resztę kodu HTML strony z serwera.

Jeśli skorzystasz z tej metody, nie będziesz tworzyć kodu HTML na kliencie, ale błyskawiczne wczytywanie fragmentów treści z pamięci podręcznej będzie sprawiało wrażenie, że witryna wczytuje się szybko. Witryny stosujące to podejście mogą wydawać się SPA prawie jak SPA, ale bez niedogodności związanych z renderowaniem po stronie klienta. Ponadto zmniejsza ilość kodu HTML, który jest żądany do serwera.

Krótko mówiąc, architektura instancji roboczych usługi strumieniowego przesyłania danych nie zastępuje wbudowanej logiki nawigacji przeglądarki, a jedynie ją uzupełni. Więcej informacji o tym, jak osiągnąć ten cel za pomocą Workbox, znajdziesz w artykule Szybsze aplikacje wielostronicowe ze strumieniami.

Podsumowanie

Sposób odbierania i renderowania kodu HTML w witrynie ma wpływ na jej wydajność. Jeśli serwer wysyła cały (lub większość) kod HTML wymagany do działania witryny, zyskujesz korzyści: przyrostowe analizowanie i renderowanie oraz automatyczne generowanie w wątku głównym, aby uniknąć długich zadań.

Renderowanie HTML po stronie klienta stwarza szereg potencjalnych problemów z wydajnością, których w wielu przypadkach można uniknąć. Jednak ze względu na wymagania danej witryny nie jest to możliwe w 100% przypadków. Aby ograniczyć potencjalne długie zadania, które mogą być spowodowane nadmiernym renderowaniem stron klienta, upewnij się, że wysyłasz jak najwięcej kodu HTML swojej witryny z serwera, staraj się, aby rozmiary DOM były jak najmniejsze dla kodu HTML, który musi być renderowany na kliencie, i rozważ alternatywne architektury, aby przyspieszyć dostarczanie kodu HTML do klienta, wykorzystując przyrostową analizę i renderowanie, które przeglądarka zapewnia w przypadku wczytywania kodu HTML z serwera.

Jeśli możesz ograniczyć renderowanie po stronie klienta do minimum, poprawisz nie tylko INP witryny, ale też inne dane, np. LCP, TBT, a w niektórych przypadkach nawet TTFB.

Baner powitalny z filmu Unsplash, którego autorem jest Maik Jonietz.