Nie walcz ze skanerem wstępnego wczytywania przeglądarki

Dowiedz się, czym jest skaner wstępnego wczytywania w przeglądarce i w jaki sposób zwiększa wydajność, oraz dowiedz się, jak się przed nim chronić.

Jedną z pominiętych aspektów optymalizacji szybkości strony jest wiedza o funkcjach wewnętrznych przeglądarki. Przeglądarki przeprowadzają pewne optymalizacje poprawiające wydajność w sposób, którego my nie możemy wspomóc dla programistów, ale tylko pod warunkiem, że optymalizacje nie będą nieumyślnie zakłócane.

Jedną z wewnętrznych metod optymalizacji, która pozwala zrozumieć działanie przeglądarek, jest skaner wstępnego wczytywania. Z tego posta dowiesz się, jak działa skaner wstępnego wczytywania i przede wszystkim, jak możesz go uniknąć.

Czym jest skaner wstępnego wczytywania?

Każda przeglądarka ma podstawowy parser HTML, który tokenizuje nieprzetworzone znaczniki i przetwarza je w modelu obiektowym. Wszystko to przebiega płynnie, dopóki parser nie zatrzyma się, gdy znajdzie zasób blokujący, np. arkusz stylów załadowany z elementem <link> lub skrypt załadowany z elementem <script> bez atrybutu async lub defer.

Diagram parsera HTML.
Rys. 1. Schemat blokowania podstawowego parsera HTML przeglądarki. W tym przypadku parser uruchamia element <link> zewnętrznego pliku CSS, który blokuje przeglądarce możliwość analizowania reszty dokumentu (lub nawet wyrenderowania jego elementów) do czasu pobrania i przeanalizowania kodu CSS.

W przypadku plików CSS zarówno analizowanie, jak i renderowanie jest blokowane, aby zapobiec przebłysku niesformatowanej treści (FOUC), czyli sytuacji, gdy niesformatowana wersja strony może zostać na krótko widoczna przed zastosowaniem stylów.

Strona główna web.dev bez stylu (po lewej) ze stylem (po prawej).
Rys. 2. Symulowany przykład FOUC. Po lewej znajduje się pierwsza strona web.dev bez stylów. Po prawej ta sama strona z zastosowanymi stylami. Stan niesformatowania może wystąpić w ciągu błyskawicznego, jeśli przeglądarka nie blokuje renderowania podczas pobierania i przetwarzania arkusza stylów.

Przeglądarka blokuje również analizowanie i renderowanie strony, jeśli natrafi na elementy <script> bez atrybutu defer lub async.

Powodem jest to, że przeglądarka nie ma pewności, czy dany skrypt będzie modyfikować DOM, podczas gdy podstawowy parser HTML nadal wykonuje swoje zadanie. Właśnie dlatego tak powszechną praktyką jest ładowanie kodu JavaScript na końcu dokumentu, by skutki zablokowania analizy i renderowania były marginalne.

Z tych powodów przeglądarka powinna blokować zarówno analizowanie, jak i renderowanie. Jednak zablokowanie jednego z tych ważnych kroków jest niepożądane, ponieważ może opóźnić odkrywanie innych ważnych zasobów. Na szczęście przeglądarki starają się rozwiązać te problemy, korzystając z dodatkowego parsera HTML nazywanego skanerem wstępnego wczytywania.

Diagram podstawowego parsera HTML (po lewej) i skanera wstępnego wczytywania (po prawej) – dodatkowego parsera HTML.
Rys. 3. Diagram pokazujący, jak skaner wstępnego wczytywania działa równolegle z podstawowym parserem HTML w celu spekulacyjnego ładowania zasobów. W tym przypadku podstawowy parser HTML jest blokowany podczas wczytywania i przetwarzania kodu CSS, zanim rozpocznie przetwarzanie znaczników obrazu w elemencie <body>, ale skaner wstępnego wczytywania może za pomocą nieprzetworzonych znaczników znaleźć ten zasób graficzny i rozpocząć jego wczytywanie, zanim zostanie odblokowany główny parser HTML.

Rola skanera wstępnego ładowania ma charakter spekulacyjny, co oznacza, że analizuje nieprzetworzone znaczniki w celu znalezienia zasobów do pobrania, zanim podstawowy parser HTML wykryje je w innym przypadku.

Jak sprawdzić, czy skaner wstępnego wczytywania działa

Skaner wstępnego wczytywania istnieje ze względu na zablokowane renderowanie i analizę. Gdyby te 2 problemy z wydajnością nie występowały, skaner wstępnego wczytywania nie byłby przydatny. Kryterium tych zjawisk blokujących jest kluczowe dla określenia, czy użycie skanera wstępnego wczytywania jest korzystne dla strony. Aby to zrobić, możesz wprowadzić sztuczne opóźnienie w odpowiedzi na żądania sprawdzenia, gdzie działa skaner wstępnego wczytywania.

Dla przykładu przyjrzyj się tej stronie zawierającej podstawowy tekst i obrazy z arkuszem stylów. Pliki CSS blokują renderowanie i analizę, dlatego wprowadzasz sztuczne opóźnienie arkusza stylów o 2 sekundy za pośrednictwem usługi pośredniczącej. Dzięki temu opóźnienie w kaskadzie sieci jest łatwiejsze, w którym działa skaner wstępnego wczytywania.

Wykres kaskadowy sieci WebPageTest ilustruje sztuczne opóźnienie wynoszące 2 sekundy nałożone na arkusz stylów.
Rys. 4. WebPageTest kaskadowy wykres sieci strony internetowej uruchamiany w Chrome na urządzeniu mobilnym przez symulowane połączenie 3G. Mimo że arkusz stylów jest sztucznie opóźniony przez serwer proxy o dwie sekundy przed rozpoczęciem ładowania, skaner wstępnego wczytywania wykrywa obraz znajdujący się później w ładunku znaczników.

Jak widać w kaskadzie, skaner wstępnego wczytywania wykrywa element <img>, nawet jeśli renderowanie i analiza dokumentów są zablokowane. Bez tej optymalizacji przeglądarka nie jest w stanie pobierać dodatkowych elementów w okresie blokowania, a więcej żądań zasobów byłoby następujących po sobie, a nie równocześnie.

Skoro już omówiliśmy ten przykład z zabawkami, spójrzmy na pewne realistyczne wzorce, w których skaner wstępnie ładowanego systemu może się skończyć oraz co można zrobić, by rozwiązać ten problem.

Wstrzyknięto async skryptu

Załóżmy, że w pliku <head> masz kod HTML zawierający wbudowany JavaScript, taki jak:

<script>
  const scriptEl = document.createElement('script');
  scriptEl.src = '/yall.min.js';

  document.head.appendChild(scriptEl);
</script>

Domyślnie wstrzyknięty skrypt ma wartość async, więc po wstrzykiwaniu będzie on zachowywać się tak, jakby został do niego zastosowany atrybut async. Oznacza to, że będzie ona uruchamiana jak najszybciej i nie będzie blokowała renderowania. Brzmi optymalnie, prawda? Jeśli jednak przy założeniu, że ten wbudowany <script> występuje po elemencie <link>, który wczytuje zewnętrzny plik CSS, otrzymasz nieoptymalny wynik:

Ten wykres WebPageTest pokazuje, jak skanowanie wstępne zostało przerwane podczas wstrzykiwania skryptu.
Rys. 5. Kaskadowy wykres kaskadowy aplikacji WebPageTest przedstawiający stronę internetową w Chrome na urządzeniu mobilnym przez symulowane połączenie 3G. Strona zawiera pojedynczy arkusz stylów i wstrzyknięty skrypt async. Skaner wstępnego wczytywania nie może wykryć skryptu w fazie blokowania renderowania, ponieważ został on wstrzykiwany po kliencie.

Opiszmy to, co się tutaj wydarzyło:

  1. W momencie 0 sekund wymagane jest przesłanie dokumentu głównego.
  2. Po 1, 4 sekundy pojawia się pierwszy bajt żądania nawigacji.
  3. W 2, 0 sekundy są wysyłane żądania CSS i obraz.
  4. Parser jest zablokowany wczytywaniu arkusza stylów, a wbudowany kod JavaScript, który wstawia skrypt async, pojawia się później od 2,6 sekundy tego arkusza, dlatego funkcje tego skryptu nie są dostępne tak szybko, jak to możliwe.

Nie jest to optymalne, ponieważ żądanie skryptu następuje dopiero po zakończeniu pobierania arkusza stylów. To spowoduje opóźnienie wykonania skryptu tak szybko, jak to możliwe. Element <img> jest natomiast wykrywalny w znacznikach dostarczanych przez serwer. Dlatego skaner wstępnego wczytywania wykrywa go.

Co się więc stanie, gdy użyjesz zwykłego tagu <script> z atrybutem async, a nie wstawić skrypt do DOM?

<script src="/yall.min.js" async></script>

Oto rezultat:

Kaskada sieciowa WebPageTest przedstawiająca sposób, w jaki skrypt asynchroniczny wczytywany przy użyciu elementu skryptu HTML jest nadal wykrywalny przez skaner wstępnego wczytywania przeglądarki, mimo że główny parser HTML przeglądarki jest zablokowany podczas pobierania i przetwarzania arkusza stylów.
Rys. 6. Wykres kaskadowy sieci WebPageTest przedstawiający stronę internetową w Chrome na urządzeniu mobilnym przez symulowane połączenie 3G. Strona zawiera 1 arkusz stylów i 1 element async <script>. Skaner wstępnego wczytywania wykrywa skrypt w fazie blokowania renderowania i wczytuje go równolegle z CSS.

Niektórzy użytkownicy mogą sugerować, że te problemy można rozwiązać za pomocą narzędzia rel=preload. To oczywiście zadziała, ale może wiązać się z pewnymi skutkami ubocznymi. Po co więc używać rel=preload do rozwiązania problemu, którego można uniknąć, nie wstrzykiując elementu <script> do DOM?

Kaskada WebPageTest pokazująca, jak wskazówka na temat zasobu rel=preload jest wykorzystywana do promowania wykrywania wstrzykiwanego skryptu asynchronicznego, choć może mieć niezamierzone skutki uboczne.
Rys. 7. Sieciowy wykres kaskadowy WebPageTest przedstawiający stronę internetową w Chrome na urządzeniu mobilnym przez symulowane połączenie 3G. Strona zawiera 1 arkusz stylów i wstrzyknięty skrypt async, ale skrypt async jest wstępnie wczytany, aby mieć pewność, że zostanie wykryty szybciej.

Wstępne wczytywanie „rozwiązuje” ten problem, ale wywołuje nowy problem: skrypt async w pierwszych 2 wersjach demonstracyjnych (pomimo załadowania w <head>) jest ładowany z najniższym priorytetem, a arkusz stylów – z priorytetem „Najwyższy”. W ostatniej wersji demonstracyjnej, w której skrypt async jest wstępnie wczytywany, arkusz stylów jest nadal wczytywany z najwyższym priorytetem, ale jego priorytet został zwiększony do „Wysoki”.

Gdy priorytet zasobu jest podniesiony, przeglądarka przydziela mu większą przepustowość. Oznacza to, że chociaż arkusz stylów ma najwyższy priorytet, zwiększony priorytet skryptu może powodować rywalizację o przepustowość. Może to powodować powolne połączenia lub bardzo duże zasoby.

Odpowiedź jest prosta: jeśli podczas uruchamiania potrzebny jest skrypt, nie pokonuj skanera wstępnego wczytywania, wstrzykijąc go do DOM. W razie potrzeby poeksperymentuj z umiejscowieniem elementu <script> oraz takimi atrybutami jak defer i async.

Leniwe ładowanie z użyciem JavaScriptu

Leniwe ładowanie to świetna metoda zachowania danych, którą często stosuje się do obrazów. Czasami jednak leniwe ładowanie jest nieprawidłowo stosowane do obrazów w części strony widocznej na ekranie.

Stwarza to potencjalne problemy z wykrywaniem zasobów w przypadku skanera wstępnego ładowania i może niepotrzebnie opóźniać znalezienie odniesienia do obrazu, pobranie go, zdekodowanie i prezentowanie. Weźmy na przykład te znaczniki obrazu:

<img data-src="/sand-wasp.jpg" alt="Sand Wasp" width="384" height="255">

Prefiks data- jest często używany przez leniwe ładowanie oparte na języku JavaScript. Gdy obraz znajdzie się w widocznym obszarze, leniwe ładowanie usuwa prefiks data-, co oznacza, że w poprzednim przykładzie data-src zmienia się w src. Ta aktualizacja spowoduje, że przeglądarka pobierze zasób.

Ten wzorzec nie stanowi problemu, dopóki nie zostanie zastosowany do obrazów, które znajdują się w widocznym obszarze podczas uruchamiania. Skaner wstępnego wczytywania nie odczytuje atrybutu data-src w taki sam sposób jak w atrybutach src (lub srcset), dlatego odwołanie do obrazu nie zostało wykryte wcześniej. Co gorsza, obraz może się wczytać dopiero po pobraniu, skompilowaniu i wykonaniu kodu JavaScript przez leniwe ładowanie.

Wykres kaskadowy sieci WebPageTest pokazujący, że leniwie ładowany obraz, który znajduje się w widocznym obszarze podczas uruchamiania, musi być opóźniony, ponieważ skaner wstępnego wczytywania w przeglądarce nie może znaleźć zasobu obrazu i wczytuje się tylko wtedy, gdy jest wymagany JavaScript do tego procesu. Obraz zostaje wykryty znacznie później, niż powinien.
Rys. 8. Sieciowy wykres kaskadowy WebPageTest przedstawiający stronę internetową w Chrome na urządzeniu mobilnym przez symulowane połączenie 3G. Zasób obrazu jest niepotrzebnie ładowany leniwie, mimo że jest widoczny w widocznym obszarze podczas uruchamiania. Uniemożliwia to modułowi wstępnego ładowania i powoduje niepotrzebne opóźnienie.

W zależności od rozmiaru obrazu – który może zależeć od rozmiaru widocznego obszaru – może on być elementem kandydującym do największego wyrenderowania treści (LCP). Gdy skaner wstępnego wczytywania nie może spekulacyjnie pobrać zasobu obrazu z wyprzedzeniem – na przykład w momencie, w którym doszło do renderowania blokowego arkuszy stylów strony – na tym korzystnie wpływa ten wskaźnik.

Rozwiązaniem jest zmiana znaczników obrazu:

<img src="/sand-wasp.jpg" alt="Sand Wasp" width="384" height="255">

To optymalny wzorzec dla obrazów, które znajdują się w widocznym obszarze podczas uruchamiania, ponieważ skaner wstępnego wczytywania szybciej wykrywa i pobiera zasób obrazu.

Wykres kaskadowy sieci WebPageTest przedstawiający scenariusz wczytywania obrazu w widocznym obszarze podczas uruchamiania. Obraz nie jest ładowany leniwie, co oznacza, że nie zależy od skryptu, co oznacza, że skaner wstępnego wczytywania może wykryć go wcześniej.
Rys. 9. Wykres kaskadowy sieci WebPageTest przedstawiający stronę internetową w Chrome na urządzeniu mobilnym przez symulowane połączenie 3G. Skaner wstępnego wczytywania wykrywa zasób obrazu, zanim zaczną się ładować CSS i JavaScript, dzięki czemu przeglądarka może zacząć go załadować.

W wyniku tego uproszczonego przykładu mamy do czynienia z poprawką wskaźnika LCP o 100 milisekund w przypadku wolnego połączenia. Może się to wydawać niezwykłe, ale okazuje się, że rozwiązaniem jest szybka poprawka znaczników, a większość stron internetowych jest bardziej złożona niż ten zestaw przykładów. Oznacza to, że kandydaci LCP być może będą musieli konkurować o przepustowość z wieloma innymi zasobami, a takie optymalizacje stają się coraz ważniejsze.

Obrazy tła CSS

Pamiętaj, że skaner wstępnie wczytuje znaczniki w przeglądarce. Nie skanuje innych typów zasobów, takich jak CSS, co może wymagać pobierania obrazów, do których odwołuje się właściwość background-image.

Podobnie jak HTML, przeglądarki przetwarzają kod CSS na własny model obiektowy, nazywany CSSOM. Jeśli zasoby zewnętrzne zostaną wykryte podczas tworzenia CSSOM, są one żądane w momencie wykrycia, a nie przez skaner wstępnego wczytywania.

Załóżmy, że kandydat LCP na Twojej stronie jest elementem z właściwością CSS background-image. Oto co dzieje się podczas wczytywania zasobów:

Wykres kaskadowy sieci WebPageTest przedstawiający stronę z kandydatem LCP wczytanym z CSS przy użyciu właściwości obrazu tła. Obraz kandydujący LCP jest typem zasobu, którego nie może przeanalizować skaner wstępnego wczytywania przeglądarki, dlatego zasób jest opóźniony od wczytania do momentu pobrania i przetworzenia arkusza CSS, co opóźnia czas wyrenderowania kandydata LCP.
Rys. 10. Wykres kaskadowy sieci WebPageTest przedstawiający stronę internetową uruchomioną w Chrome na urządzeniu mobilnym przez symulowane połączenie 3G. Kandydat na LCP strony to element z właściwością CSS background-image (wiersz 3). Żądany obraz nie rozpocznie się, dopóki nie znajdzie go parser CSS.

W takim przypadku skaner wstępnego wczytywania nie jest tak zaniedbany, jak żaden. Mimo to, jeśli kandydat LCP na stronie pochodzi z właściwości CSS background-image, warto wstępnie wczytać ten obraz:

<!-- Make sure this is in the <head> below any
     stylesheets, so as not to block them from loading -->
<link rel="preload" as="image" href="lcp-image.jpg">

Ta wskazówka rel=preload jest krótka, ale pomaga przeglądarce wykryć obraz szybciej niż w innym przypadku:

Wykres kaskadowy sieci WebPageTest pokazujący obraz tła CSS (kandydat LCP) ładowany znacznie szybciej ze względu na zastosowanie wskazówek rel=preload. Czas LCP wydłuża się o około 250 milisekund.
Rys. 11. Wykres kaskadowy sieci WebPageTest przedstawiający stronę internetową uruchomioną w Chrome na urządzeniu mobilnym przez symulowane połączenie 3G. Kandydat na LCP strony to element z właściwością CSS background-image (wiersz 3). Wskazówka rel=preload pozwala przeglądarce wykryć obraz około 250 milisekund szybciej niż bez niej.

Wskazówka rel=preload sprawia, że kandydat LCP jest wykrywany szybciej, co skraca czas LCP. Ta wskazówka pomaga rozwiązać ten problem, ale lepszą opcją może być sprawdzenie, czy kandydat LCP obrazu musi zostać załadowany z CSS. Tag <img> daje Ci większą kontrolę nad ładowaniem obrazu odpowiedniego do widocznego obszaru, a jednocześnie umożliwia wykrywanie tego przez skaner wstępnie załadowanego.

Wbudowano zbyt wiele zasobów

Wbudowanie to metoda polegająca na umieszczaniu zasobu w kodzie HTML. Możesz wstawiać arkusze stylów w elementach <style>, skrypty w elementach <script>, a także praktycznie w dowolnych innych zasobach za pomocą kodowania base64.

Wbudowane zasoby mogą być szybsze niż ich pobieranie, ponieważ dla zasobu nie jest wysyłane osobne żądanie. Znajduje się od razu w dokumencie i od razu się wczytuje. Istnieje jednak kilka istotnych wad:

  • Jeśli nie umieszczasz kodu HTML w pamięci podręcznej (i nie możesz tego zrobić, jeśli odpowiedź HTML jest dynamiczna), wbudowane zasoby nigdy nie są zapisywane w pamięci podręcznej. Wpływa to na wydajność, ponieważ wbudowanych zasobów nie nadają się do wielokrotnego użytku.
  • Nawet jeśli możesz zapisać kod HTML w pamięci podręcznej, zasoby wbudowane nie są współdzielone między dokumentami. Zmniejsza to wydajność buforowania w porównaniu z plikami zewnętrznymi, które można przechowywać w pamięci podręcznej i ponownie wykorzystywać w całym punkcie początkowym.
  • Jeśli w tekście jest za dużo treści, skaner wstępnego wczytywania nie wykrywa zasobów w dalszej części dokumentu, ponieważ pobieranie tych treści trwa dłużej.

Dla przykładu przyjrzyj się tej stronie. W pewnych warunkach kandydat LCP jest obrazem na górze strony, a plik CSS znajduje się w osobnym pliku wczytywanym przez element <link>. Strona korzysta również z czterech czcionek internetowych, które są żądane jako osobne pliki z zasobem CSS.

Sieciowy wykres kaskadowy WebPageTest przedstawiający stronę z zewnętrznym plikiem CSS i czterema czcionkami, do których odwołują się 4 czcionki. Obraz kandydata LCP zostaje wykryty przez skaner wstępnego wczytywania.
Rys. 12. Wykres kaskadowy sieci WebPageTest przedstawiający stronę internetową uruchomioną w Chrome na urządzeniu mobilnym przez symulowane połączenie 3G. Kandydat na LCP strony to obraz wczytywany z elementu <img>, ale zostaje wykryty przez skaner wstępnego wczytywania, ponieważ CSS i czcionki wymagane do załadowania strony są umieszczane w osobnych zasobach, co nie opóźnia zadania skanera wstępnego wczytywania.

Co się teraz stanie, jeśli CSS i wszystkie czcionki będą wstawiane jako zasoby base64?

Sieciowy wykres kaskadowy WebPageTest przedstawiający stronę z zewnętrznym plikiem CSS i czterema czcionkami, do których odwołują się 4 czcionki. Skaner wstępnego wczytywania ma znaczne opóźnienie w wykryciu obrazu LCP .
Rys. 13. Wykres kaskadowy sieci WebPageTest przedstawiający stronę internetową uruchomioną w Chrome na urządzeniu mobilnym przez symulowane połączenie 3G. Kandydat na LCP strony to obraz wczytywany z elementu <img>, ale wbudowanie kodu CSS i jego 4 zasobów czcionek w pliku „” opóźnia wykrycie obrazu przez skaner wstępnego wczytywania do czasu pełnego pobrania tych zasobów.

W tym przykładzie wpływ wbudowywania ma negatywne konsekwencje dla LCP, a także na ogólnie wyniki. Wersja strony, która nie ma w tekście żadnego elementu wbudowanego, obrazuje obraz LCP w ciągu ok.3,5 sekundy. Strona, na której znajdziesz wszystkie elementy, nie maluje obrazu LCP przed ponad 7 sekundami.

Nie tylko skaner wstępnego wczytywania. Wbudowanie czcionek nie jest dobrym rozwiązaniem, ponieważ base64 nie jest wydajnym formatem dla zasobów binarnych. Innym czynnikiem jest to, że zewnętrzne zasoby czcionek nie są pobierane, jeśli nie zostaną uznane za konieczne przez CSSOM. Czcionki te są pobierane w standardzie base64 i niezależnie od tego, czy są potrzebne na bieżącej stronie.

Czy wstępne załadowanie może coś tu poprawić? Oczywiście. Możesz wstępnie wczytać obraz LCP i skrócić czas LCP, ale przesłanie kodu HTML, którego nie można zapisać w pamięci podręcznej, za pomocą wbudowanych zasobów ma inne negatywne konsekwencje związane z wydajnością. Ten wzorzec ma również wpływ na pierwsze wyrenderowanie treści (FCP). W wersji strony, na której nic nie znajduje się w tekście, wskaźnik FCP wynosi około 2,7 sekundy. W wersji, w której wszystko jest w tekście, FCP wynosi około 5,8 sekundy.

Zachowaj szczególną ostrożność przy wbudowywaniu treści do kodu HTML, zwłaszcza w przypadku zasobów zakodowanych w formacie base64. Ogólnie nie jest to zalecane z wyjątkiem bardzo małych zasobów. Wbudowane jak najmniej, ponieważ za dużo w treści to ingerencje w świat ognia.

Renderowanie znaczników za pomocą kodu JavaScript po stronie klienta

Nie ma co do tego wątpliwości: JavaScript ma zdecydowanie wpływ na szybkość działania strony. Deweloperzy nie tylko polegają na niej, aby zapewnić interaktywność, ale też na samo dostarczanie treści. Pod pewnymi względami poprawia to wygodę programistów, ale korzyści dla deweloperów nie zawsze przekładają się na korzyści dla użytkowników.

Jednym z wzorców, który może pokonać skaner wstępnego wczytywania, jest renderowanie znaczników za pomocą JavaScriptu po stronie klienta:

Kaskada sieci WebPageTest wyświetlająca podstawową stronę z obrazami i tekstem renderowanym w całości po stronie klienta w języku JavaScript. Ponieważ znaczniki są zawarte w kodzie JavaScript, skaner wstępnego wczytywania nie jest w stanie wykryć żadnych zasobów. Wszystkie zasoby są dodatkowo opóźnione z powodu dodatkowego czasu trwania sieci i czasu przetwarzania, którego wymagają platformy JavaScript.
Rys. 14. Wykres kaskadowy sieci WebPageTest przedstawiający stronę internetową wyrenderowaną przez klienta w Chrome na urządzeniu mobilnym przez symulowane połączenie 3G. Ponieważ treść jest zawarta w języku JavaScript i wykorzystywana jest platforma renderowania, zasób obrazu w znacznikach renderowanych przez klienta jest ukryty przed skanerem wstępnego wczytywania. Odpowiednik renderowany przez serwer jest przedstawiony na Rys. 9.

Gdy ładunki znaczników są w przeglądarce zawarte i w pełni renderowane przez JavaScript, wszelkie zawarte w nich zasoby są w praktyce niewidoczne dla skanera wstępnego wczytywania. Opóźnia to wykrywanie ważnych zasobów, co z pewnością wpływa na LCP. W tych przykładach żądanie obrazu LCP jest znacznie opóźnione w porównaniu z odpowiednim renderowaniem przez serwer, które nie wymaga JavaScriptu.

Ten artykuł odbiega od tematu tego artykułu, ale wpływ renderowania znaczników na klienta jest znacznie bardziej skomplikowany niż skaner wstępnego wczytywania. Po pierwsze, wprowadzenie JavaScriptu w celu zwiększenia wydajności, które nie wymaga więcej czasu, wiąże się z wprowadzaniem niepotrzebnego czasu przetwarzania, który może mieć wpływ na interakcję z następnym wyrenderowaniem (INP). Renderowanie bardzo dużych ilości znaczników na kliencie daje większe prawdopodobieństwo wygenerowania długich zadań niż tyle samo znaczników wysyłanych przez serwer. Powodem, oprócz dodatkowego przetwarzania, który wymaga JavaScript, jest to, że przeglądarki przesyłają strumieniowo znaczniki z serwera i dzielą renderowanie w sposób, który zazwyczaj ogranicza długie zadania. Znaczniki renderowane przez klienta są natomiast obsługiwane jako pojedyncze, monolityczne zadanie, które może wpływać na wartość INP strony.

Rozwiązanie tego problemu zależy od odpowiedzi na to pytanie: Czy istnieje powód, dla którego serwer nie może zapewnić znaczników strony zamiast renderowania na kliencie? Jeśli odpowiedź brzmi „nie”, w miarę możliwości warto wziąć pod uwagę renderowanie po stronie serwera (SSR) lub statycznie wygenerowane znaczniki. Pomoże to skanerowi wstępnego wczytywania i oszczędnego pobrania ważnych zasobów z wyprzedzeniem.

Jeśli Twoja strona wymaga JavaScriptu, by dodać funkcje do niektórych części znaczników strony, nadal możesz to zrobić za pomocą SSR – za pomocą JavaScriptu waniliowego lub hydratacji – pozwoli to wykorzystać oba te elementy.

Pomóż skanerowi wstępnego wczytywania

Skaner wstępnego wczytywania to bardzo skuteczna optymalizacja przeglądarki, która przyspiesza wczytywanie stron podczas uruchamiania. Unikanie wzorców, które uniemożliwiałyby wykrywanie ważnych zasobów z wyprzedzeniem, nie tylko ułatwiasz sobie programowanie, ale także zapewniasz użytkownikom lepsze wrażenia, co przekłada się na lepsze wyniki pod względem wielu rodzajów danych, w tym niektórych wskaźników internetowych.

Oto czego należy się z niego dowiedzieć:

  • Skaner wstępnego wczytywania przeglądarki to dodatkowy parser HTML, który skanuje przed nadrzędnym, jeśli jest zablokowany, aby umożliwić wyszukiwanie zasobów, które może pobrać wcześniej.
  • Skaner wstępnego wczytywania nie wykrywa zasobów, których nie ma w znacznikach podanych przez serwer w pierwszym żądaniu nawigacji. Skaner wstępnego ładowania może zostać przesunięty na skutek m.in.:
    • Wstrzykiwanie do DOM za pomocą JavaScriptu zasobów, np. skryptów, obrazów, arkuszy stylów lub innych elementów, które lepiej sprawdzi się w początkowym ładunku znaczników z serwera.
    • Leniwe ładowanie obrazów w części strony widocznej na ekranie lub elementów iframe za pomocą rozwiązania JavaScript.
    • Znaczniki renderowania po stronie klienta, które mogą zawierać odwołania do zasobów podrzędnych dokumentu za pomocą JavaScriptu.
  • Skaner wstępnego wczytywania skanuje tylko kod HTML. Nie analizuje zawartości innych zasobów – w szczególności CSS – które mogą zawierać odwołania do ważnych zasobów, w tym kandydatów LCP.

Jeśli z jakiegokolwiek powodu nie możesz uniknąć wzorca, który negatywnie wpływa na zdolność skanera wstępnego wczytywania, zastosuj wskazówkę dotyczącą zasobów rel=preload. Jeśli używasz metody rel=preload, przetestuj ją w narzędziach laboratoryjnych, aby upewnić się, że przynosi pożądany efekt. Nie ładuj wstępnie zbyt wielu zasobów, bo jeśli ustalisz priorytety dla wszystkich, nic się nie stanie.

Zasoby

Baner powitalny z filmu Unsplash, którego autorem jest Mohammad Rahmani .