Nie walcz ze skanerem wstępnego wczytywania przeglądarki

Dowiedz się, czym jest skaner wstępnego wczytywania przeglądarki, jak zwiększa jego wydajność i jak możesz uniknąć zakłóceń.

Jednym z pominiętych aspektów optymalizacji szybkości stron jest znajomość wewnętrznych funkcji przeglądarki. Przeglądarki wprowadzają pewne optymalizacje, aby poprawić wydajność w sposób, który nie jest możliwe dla programistów – ale tylko pod warunkiem, że nie uda im się w sposób nieumyślny wpłynąć na te optymalizacje.

Jednym z wewnętrznych funkcji optymalizacji przeglądarki jest skaner wstępnego wczytywania przeglądarki. W tym poście omówimy, jak działa skaner wstępnego wczytywania, a przede wszystkim dowiesz się, jak tego uniknąć.

Co to jest skaner wstępnego wczytywania?

Każda przeglądarka ma główny parser HTML, który tokenizuje nieprzetworzone znaczniki i przetwarza je w model obiektowy. Wszystko to dzieje się tak długo, aż parser się nie zatrzyma, gdy znajdzie zasób blokujący, np. arkusz stylów wczytany z elementem <link> lub skrypt wczytany z elementem <script> bez atrybutu async lub defer.

Diagram parsera HTML.
Rys. 1. Diagram sposobu blokowania głównego parsera HTML przeglądarki. W tym przypadku parser korzysta z elementu <link> zewnętrznego pliku CSS, który uniemożliwia przeglądarce analizowanie reszty dokumentu (a nawet renderowanie dowolnego z nich) do czasu pobrania i przeanalizowania arkusza CSS.

W przypadku plików CSS zarówno analizowanie, jak i renderowanie jest blokowane, aby uniknąć przebłysku niespójnej treści (FOUC), czyli sytuacji, gdy przed zastosowaniem stylów można zobaczyć wersję strony bez stylu.

Strona główna web.dev w stanie bez stylu (po lewej) i ze stylem (po prawej).
Rys. 2. Symulowany przykład FOUC. Po lewej stronie widoczna jest pierwsza strona web.dev bez stylów. Po prawej stronie widać tę samą stronę z zastosowanymi stylami. Brak stylu może wystąpić we Flashu, jeśli przeglądarka nie blokuje renderowania podczas pobierania i przetwarzania arkusza stylów.

Przeglądarka blokuje też analizowanie i renderowanie strony w przypadku napotkania elementów <script> bez atrybutu defer lub async.

Dzieje się tak, ponieważ przeglądarka nie może stwierdzić, czy którykolwiek z skryptów zmieni model DOM, gdy podstawowy parser HTML będzie wykonywał swoje zadanie. Właśnie dlatego często ładuj kod JavaScript na końcu dokumentu, aby skutki zablokowanego analizowania i renderowania były minimalne.

Oto dobre powody, dla których przeglądarka powinna blokować zarówno analizowanie, jak i renderowanie. Jednak zablokowanie któregokolwiek z tych ważnych kroków jest niepożądane, ponieważ może je wstrzymać, opóźniając znalezienie innych ważnych zasobów. Na szczęście te przeglądarki starają się radzić sobie z tym problemem dzięki dodatkowemu parserowi HTML, zwanemu skanerem wstępnego wczytywania.

Diagram podstawowego parsera HTML (po lewej) i skanera wstępnego wczytywania (po prawej), który jest dodatkowym parserem HTML.
Rys. 3. Diagram prezentujący, jak skaner wstępnego wczytywania działa równolegle z podstawowym parserem HTML w celu spekulatywnego wczytywania zasobów. W tym przypadku podstawowy parser HTML jest blokowany podczas wczytywania i przetwarzania CSS, zanim rozpocznie przetwarzanie znaczników obrazu w elemencie <body>. Skaner wstępnego wczytywania może jednak wyszukać zasób obrazu i zacząć go ładować, zanim podstawowy parser HTML zostanie odblokowany.

Rola skanera wstępnego jest spekulacyjna, co oznacza, że sprawdza nieprzetworzone znaczniki w celu znalezienia zasobów do pobrania oportunistycznego, zanim główny parser HTML je wykryje.

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

Skaner wstępnego wczytywania istnieje z powodu zablokowania renderowania i analizowania. Gdyby te 2 problemy z wydajnością nie występowały, skaner wstępnego wczytywania nie byłby zbyt przydatny. Kluczem do ustalenia, czy skaner wstępnego wczytywania strony będzie używany, zależy od tych zjawisk blokujących. W tym celu możesz wprowadzić sztuczne opóźnienie żądań informacji o tym, gdzie działa skaner wstępnego wczytywania.

Weźmy jako przykład tę stronę zawierającą tekst i obrazy z arkuszem stylów. Ponieważ pliki CSS blokują zarówno renderowanie, jak i analizowanie, użytkownik wprowadza sztuczne opóźnienie dla arkusza stylów wynoszące dwa sekundy za pośrednictwem usługi proxy. Dzięki temu łatwiej jest zobaczyć w kaskadzie sieci, gdzie 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 z symulowanym połączeniem 3G. Mimo że serwer proxy jest sztucznie opóźniony w przypadku wczytywania arkusza stylów o dwie sekundy przed rozpoczęciem ładowania, skaner wstępnego wczytywania wykrywa obraz znajdujący się w dalszej części ładunku znaczników.

Jak widać w kaskadzie, skaner wstępnego wczytywania wykrywa element <img> nawet wtedy, gdy renderowanie i analiza dokumentu jest zablokowane. Bez tej optymalizacji przeglądarka nie może w trakcie okresu blokowania pobierać treści w osobisty sposób, a więcej żądań zasobów odbywałoby się kolejno po sobie, a nie równocześnie.

Teraz spójrzmy na przykłady rzeczywistych wzorców, w których można zapobiec skanerowi wstępnego wczytywania, a także co można zrobić, by te problemy rozwiązać.

Wstrzyknięto async skryptu

Załóżmy, że w sekcji <head> masz kod HTML, który zawiera wbudowany kod JavaScript, taki jak:

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

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

Wstrzykiwane skrypty mają wartość domyślną async, więc po wstawieniu skryptu działa on tak, jakby został do niego zastosowany atrybut async. Oznacza to, że zacznie on działać jak najszybciej i nie będzie blokować renderowania. Brzmi optymalnie, prawda? Jeśli jednak przyjmiesz, że wbudowany element <script> znajduje się po elemencie <link>, który wczytuje zewnętrzny plik CSS, otrzymasz nieoptymalny wynik:

Ten wykres WebPageTest pokazuje, jak skanowanie wstępnego wczytywania zostało przerwane po wstrzykiwaniu skryptu.
Rys. 5. Wykres kaskadowy sieci WebPageTest przedstawiający stronę internetową, uruchamiany w Chrome na urządzeniu mobilnym z symulowanym połączeniem 3G. Strona zawiera jeden arkusz stylów i wstrzyknięty skrypt async. Skaner wstępnego wczytywania nie może wykryć skryptu w trakcie blokowania renderowania, ponieważ jest on wstrzykiwany przez klienta.

Przeanalizujmy, co się wydarzyło:

  1. W 0 sekundach jest wysyłane żądanie dokumentu głównego.
  2. Po 1, 4 sekundy przychodzi pierwszy bajt żądania nawigacji.
  3. Po 2 sekundzie wymagane jest żądanie CSS i obrazu.
  4. Ponieważ parser blokuje wczytywanie arkusza stylów, a wbudowany skrypt JavaScript, który wstrzykuje skrypt async, pojawia się po 2,6 sekundy tego arkusza stylów, dlatego funkcje zapewniane przez skrypt nie są dostępne tak szybko, jak by mogły.

Jest to nieoptymalne, ponieważ żądanie skryptu jest wysyłane dopiero po zakończeniu pobierania arkusza stylów. Spowoduje to jak najszybsze uruchomienie skryptu. Element <img> jest natomiast wykrywalny w znacznikach dostarczanych przez serwer, dlatego zostaje wykryty przez skaner wstępnego wczytywania.

Co się więc stanie, jeśli użyjesz zwykłego tagu <script> z atrybutem async zamiast wstrzyknięcia skryptu w DOM?

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

Wynik to:

Kaskada sieci 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 blokowany podczas pobierania i przetwarzania arkusza stylów.
Rys. 6. Wykres kaskadowy sieci WebPageTest przedstawiający stronę internetową, uruchamiany w Chrome na urządzeniu mobilnym z symulowanym połączeniem 3G. Strona zawiera jeden arkusz stylów i jeden element async <script>. Skaner wstępnego wczytywania wykrywa skrypt w trakcie fazy blokowania renderowania i wczytuje go równocześnie z kodem CSS.

Może się wydawać, że te problemy można rozwiązać przy użyciu rel=preload. Z pewnością to zadziała, ale może mieć pewne skutki uboczne. W końcu po co używać rel=preload do rozwiązywania problemu, którego można uniknąć, nie wstawiając elementu <script> w DOM?

Kaskada WebPageTest pokazująca, jak wskazówka dotycząca zasobu rel=preload jest wykorzystywana do promowania wykrywania skryptu z wstrzykniętego skryptu asynchronicznego – choć w sposób, który może mieć niezamierzone efekty uboczne.
Rys. 7. Wykres kaskadowy sieci WebPageTest przedstawiający stronę internetową, uruchamiany w Chrome na urządzeniu mobilnym z symulowanym połączeniem 3G. Strona zawiera jeden arkusz stylów i wstrzyknięty skrypt async, ale skrypt async jest wstępnie wczytywany, aby zapewnić jego szybsze wykrycie.

Wstępne wczytywanie tego problemu „rozwiązuje” ten problem, ale wprowadza nowy problem: skrypt async w dwóch pierwszych wersjach demonstracyjnych – pomimo wczytania w środowisku <head> – jest wczytywany z priorytetem „Niski”, a arkusz stylów jest wczytywany z priorytetem „Najwyższym”. W ostatniej wersji demonstracyjnej, w której został wstępnie wczytany skrypt async, arkusz stylów był nadal wczytywany z priorytetem „Najwyższy”, ale został on podniesiony do poziomu „Wysoki”.

Gdy priorytet zasobu zostanie podniesiony, przeglądarka przypisze mu większą przepustowość. Oznacza to, że nawet jeśli arkusz stylów ma najwyższy priorytet, podniesiony priorytet skryptu może powodować rywalizację z przepustowością. Może to być przyczyną powolnego połączenia lub dość dużych zasobów.

Odpowiedź jest prosta: jeśli podczas uruchamiania potrzebny jest skrypt, nie należy godzić się na skanowanie skanera, wstawiając go w modelu DOM. W razie potrzeby poeksperymentuj z rozmieszczeniem elementów typu <script> oraz z atrybutami takimi jak defer i async.

Leniwe ładowanie z użyciem JavaScriptu

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

Może to stwarzać potencjalne problemy z wykrywaniem zasobów ze względu na skaner wstępnego wczytywania. Może też niepotrzebnie opóźniać czas potrzebny na wykrycie odniesienia do obrazu, pobranie go, zdekodowanie i zaprezentowanie. Przeanalizujmy ten przykład znacznika obrazu:

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

Zastosowanie prefiksu data- jest częstym wzorcem w leniwych programach ładowania obsługiwanych przez JavaScript. Gdy obraz zostanie przewinięty do widocznego obszaru, leniwe ładowanie usuwa prefiks data-, co oznacza, że w poprzednim przykładzie data-src zmienia się w src. Ta aktualizacja zachęca przeglądarkę do pobrania zasobu.

Ten wzorzec nie stanowi problemów, dopóki nie zostanie zastosowany do obrazów, które podczas uruchamiania znajdują się w widocznym obszarze. Skaner wstępnego wczytywania nie odczytuje atrybutu data-src w taki sam sposób jak atrybut src (lub srcset), więc odwołanie do zdjęcia nie zostało wykryte wcześniej. Co gorsza, wczytywanie obrazu jest opóźnione do po pobraniu, skompilowaniu i wykonaniu kodu JavaScript leniwego ładowania.

Wykres kaskadowy sieci WebPageTest pokazujący, jak leniwe ładowanie obrazu znajdującego się w widocznym obszarze podczas uruchamiania jest zawsze opóźnione, ponieważ skaner wstępnego wczytywania przeglądarki nie może znaleźć zasobu obrazu i wczytuje się tylko wtedy, gdy wczytuje się kod JavaScript wymagany do leniwego ładowania. Obraz pojawia się znacznie później, niż powinien.
Rys. 8. Wykres kaskadowy sieci WebPageTest przedstawiający stronę internetową, uruchamiany w Chrome na urządzeniu mobilnym z symulowanym połączeniem 3G. Zasób obrazu jest niepotrzebnie wczytywany leniwie, mimo że podczas uruchamiania jest widoczny w widocznym obszarze. Spowoduje to wyłączenie skanera wstępnego wczytywania i spowoduje niepotrzebne opóźnienie.

W zależności od rozmiaru obrazu, który może zależeć od wielkości widocznego obszaru, może on też stanowić element kandydujący do największego wyrenderowania treści (LCP). Gdy skaner wstępnego wczytywania nie może spekulacyjnie pobrać zasobu graficznego z wyprzedzeniem, na przykład w czasie, gdy arkusz stylów strony blokuje renderowanie, ucierpi LCP.

Rozwiązaniem jest zmiana znaczników obrazu:

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

Jest to optymalny wzorzec w przypadku obrazów znajdujących się w widocznym obszarze podczas uruchamiania, ponieważ skaner wstępnego wczytywania będzie szybciej wykrywać i pobierać zasoby graficzne.

Wykres kaskadowy sieci WebPageTest przedstawiający scenariusz wczytywania obrazu w widocznym obszarze podczas uruchamiania. Obraz nie jest ładowany leniwie, co oznacza, że nie jest zależny od wczytania skryptu, co oznacza, że skaner wstępnego wczytywania może go wcześniej wykryć.
Rys. 9. Wykres kaskadowy sieci WebPageTest przedstawiający stronę internetową, uruchamiany w Chrome na urządzeniu mobilnym z symulowanym połączeniem 3G. Skaner wstępnego wczytywania wykrywa zasób graficzny przed rozpoczęciem wczytywania kodu CSS i JavaScriptu, dzięki czemu przeglądarka może szybciej go wczytać.

Wynikiem tego uproszczonego przykładu jest poprawa LCP o 100 milisekund w przypadku powolnego połączenia. Może to nie wydawać się wielkim usprawnieniem, ale gdy weźmiemy pod uwagę szybkie poprawki w znacznikach i większość stron internetowych jest bardziej skomplikowana niż ten zestaw przykładów. Oznacza to, że kandydaci do LCP mogą mieć trudności z rywalizowaniem o przepustowość z wieloma innymi zasobami, więc takie optymalizacje stają się coraz ważniejsze.

Obrazy tła CSS

Pamiętaj, że skaner wstępnego wczytywania przeglądarki skanuje znaczniki. Nie skanuje innych typów zasobów, takich jak CSS, co może wiązać się z pobraniem obrazów, do których odwołuje się właściwość background-image.

Podobnie jak w przypadku HTML, przeglądarki przetwarzają kod CSS we własnym modelu obiektowym o nazwie CSSOM. Jeśli podczas tworzenia CSSOM zostaną wykryte zasoby zewnętrzne, są one żądane w momencie wykrycia, a nie przez skaner wstępnego wczytywania.

Załóżmy, że kandydat LCP Twojej strony to element 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 „tle-image”. Ponieważ obraz kandydujący do LCP znajduje się w typie zasobu, którego nie może sprawdzić skaner wstępnego wczytywania przeglądarki, zasób jest opóźniony do czasu pobrania i przetworzenia CSS, co opóźni czas renderowania kandydata LCP.
Rys. 10. Wykres kaskadowy sieci WebPageTest przedstawiający stronę internetową, uruchamiany w Chrome na urządzeniu mobilnym z symulowanym połączeniem 3G. Proponowany LCP strony to element z właściwością background-image CSS (wiersz 3). Obraz, którego dotyczy żądanie, nie rozpocznie się, dopóki parser CSS go nie znajdzie.

W takim przypadku skaner wstępnego wczytywania nie jest tak bardzo zagrożony, jak i niezaangażowany. Nawet jeśli potencjalny LCP na stronie pochodzi z właściwości CSS background-image, należy wstępnie wczytywać 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 dotycząca atrybutu rel=preload jest niewielka, ale pomaga przeglądarce wykryć obraz szybciej, niż w innym przypadku:

Wykres kaskadowy sieci WebPageTest przedstawiający obraz tła w usłudze porównywania cen (kandydat do LCP) ładujący się znacznie szybciej ze względu na zastosowanie podpowiedzi rel=preload. Czas LCP zwiększa się o około 250 milisekund.
Rys. 11. Wykres kaskadowy sieci WebPageTest przedstawiający stronę internetową, uruchamiany w Chrome na urządzeniu mobilnym z symulowanym połączeniem 3G. Proponowany LCP strony to element z właściwością background-image CSS (wiersz 3). Wskazówka rel=preload pomaga przeglądarce wykryć obraz o około 250 milisekund wcześniej niż bez podpowiedzi.

Dzięki wskazówce rel=preload kandydat LCP jest odkrywany wcześniej, co skraca czas LCP. Ta wskazówka pomaga rozwiązać ten problem, ale lepszą opcją może być sprawdzenie, czy kandydujący obraz LCP został wczytany z CSS. Tag <img> daje większą kontrolę nad wczytywaniem obrazu, który pasuje do widocznego obszaru, a jednocześnie umożliwia wykrywanie tego obrazu przez skaner.

Wstawiono zbyt wiele zasobów

Wbudowanie polega na umieszczaniu zasobu w kodzie HTML. Możesz używać arkuszy stylów w elementach <style>, skryptów w elementach <script> i w praktycznie dowolnych innych zasobach, używając kodowania base64.

Wbudowanie zasobów może być szybsze niż ich pobranie, ponieważ dla danego zasobu nie jest wysyłane osobne żądanie. Znajdują się one bezpośrednio w dokumencie i są natychmiast wczytywane. Istnieją jednak poważne wady:

  • Jeśli nie umieszczasz kodu HTML w pamięci podręcznej – a nie możesz, jeśli odpowiedź HTML jest dynamiczna – zasoby wbudowane nie są przechowywane w pamięci podręcznej. Ma to wpływ na wydajność, ponieważ wbudowanych zasobów nie można używać ponownie.
  • Nawet jeśli możesz buforować kod HTML, wbudowane zasoby nie są udostępniane 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 używać w całym źródle.
  • Jeśli umieścisz je w tekście, opóźnisz skanowanie przed odszukaniem przez skaner zasobów w dalszej części dokumentu, ponieważ pobieranie dodatkowych treści w tekście trwa dłużej.

Dla przykładu wybierz tę stronę. W określonych warunkach propozycja LCP to obraz u góry strony, a kod CSS znajduje się w osobnym pliku wczytywanym przez element <link>. Strona wykorzystuje także 4 czcionki internetowe, które są żądane jako osobne pliki od zasobu CSS.

Wykres kaskadowy sieci WebPageTest przedstawiający stronę z zewnętrznym plikiem CSS z 4 czcionkami, do których odwołują się w nim. W odpowiednim czasie skaner wstępnego wczytywania znajdzie obraz kandydata LCP.
Rys. 12. Wykres kaskadowy sieci WebPageTest przedstawiający stronę internetową, uruchamiany w Chrome na urządzeniu mobilnym z symulowanym połączeniem 3G. Kandydat LCP strony to obraz wczytany z elementu <img>, ale zostaje wykryty przez skaner wstępnego wczytywania, ponieważ kod CSS i czcionki wymagane do wczytania strony znajdują się w osobnych zasobach, co nie opóźnia wykonania zadania skanera wstępnego.

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

Wykres kaskadowy sieci WebPageTest przedstawiający stronę z zewnętrznym plikiem CSS z 4 czcionkami, do których odwołują się w nim. Skaner wstępnego wczytywania jest znacznie opóźniony względem wykrycia obrazu LCP .
Rys. 13. Wykres kaskadowy sieci WebPageTest przedstawiający stronę internetową, uruchamiany w Chrome na urządzeniu mobilnym z symulowanym połączeniem 3G. Kandydat do LCP strony to obraz wczytany z elementu <img>, ale wbudowanie kodu CSS i cztery zasoby czcionki w polu „” opóźnia wykrywanie obrazu przez skaner wstępnego wczytywania, dopóki te zasoby nie zostaną w pełni pobrane.

W tym przykładzie wpływ w trakcie w reklamie wpływa negatywnie na LCP, a także na ogólną skuteczność. Wersja strony, która nie zawiera żadnych elementów w treści, tworzy obraz LCP w ciągu około 3,5 sekundy. Strona, która zawiera wszystko, maluje obraz LCP dopiero po nieco ponad 7 sekundach.

To coś więcej niż tylko skaner wstępnego wczytywania. Wbudowane czcionki nie są dobrym rozwiązaniem, ponieważ base64 nie jest skutecznym formatem dla zasobów binarnych. Innym czynnikiem jest to, że zewnętrzne zasoby czcionek nie są pobierane, chyba że CSSOM uzna je za konieczne. Jeśli czcionki te są wbudowane w standard base64, zostaną pobrane niezależnie od tego, czy są potrzebne na bieżącej stronie.

Czy wstępne wczytywanie może tu coś poprawić? Jasne. Możesz wstępnie wczytać obraz LCP i skrócić czas LCP, ale nadmierne wyświetlanie kodu HTML, którego nie można przechowywać w pamięci podręcznej, może mieć inne negatywne konsekwencje związane z wydajnością. Ten wzorzec wpływa również na pierwsze wyrenderowanie treści (FCP). W wersji strony, w której nic nie jest wbudowane, 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 włączaniu treści do kodu HTML, zwłaszcza zasobów zakodowanych w formacie base64. Ogólnie nie jest to zalecane z wyjątkiem bardzo małych zasobów. Umieść w tekście jak najmniejszą treść, bo za dużo w treści idzie ogień.

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

Co do tego nie ma wątpliwości: JavaScript z pewnością wpływa na szybkość strony. Deweloperzy nie tylko polegają na nim w zapewnieniu interaktywności, ale są też dość częste, by polegać na niej w celu dostarczania treści. Poprawia to w pewnym stopniu komfort deweloperów, ale korzyści nie zawsze przekładają się na korzyści dla użytkowników.

Jednym ze wzorców, które mogą poradzić sobie ze skanerem 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 w całości renderowanych przez klienta za pomocą JavaScriptu. Znaczniki są zawarte w kodzie JavaScript, więc skaner wstępnego wczytywania nie może wykryć żadnych zasobów. Poza tym wszystkie zasoby są opóźnione ze względu na dodatkowy czas potrzebny na obsługę sieci i przetwarzania wymagany przez platformy JavaScript.
Rys. 14. Wykres kaskadowy sieci WebPageTest przedstawiający stronę internetową renderowaną przez klienta, uruchamianą w Chrome na urządzeniu mobilnym z symulowanym połączeniem 3G. Treść jest zawarta w skrypcie JavaScript i korzysta z platformy do renderowania, dlatego zasób obrazu w znacznikach renderowanych przez klienta jest ukryty przed skanerem wstępnego wczytywania. Odpowiednik renderowany przez serwer został przedstawiony na Rys. 9.

Gdy ładunki znaczników są zawarte i renderowane w całości przez JavaScript w przeglądarce, wszystkie zasoby w tych znacznikach 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 takich przypadkach żądanie obrazu LCP jest znacznie opóźnione w porównaniu z odpowiednim procesem renderowanym przez serwer, który nie wymaga JavaScriptu.

Trochę odbiega to od tematyki tego artykułu, ale wpływ renderowania znaczników na klienta znacznie wykracza poza walkę ze skanerem wstępnego wczytywania. Po pierwsze, wprowadzenie JavaScriptu do obsługi środowiska, które nie wymaga jego obsługi, wydłuża czas przetwarzania, który może negatywnie wpływać na interakcję z kolejnym wyrenderowaniem (INP).

Poza tym renderowanie bardzo dużych ilości znaczników na kliencie zwiększa prawdopodobieństwo wygenerowania długich zadań w porównaniu z taką samą ilością znaczników wysyłanych przez serwer. Dzieje się tak, oprócz dodatkowego przetwarzania związanego z JavaScriptem, ponieważ przeglądarki przesyłają znaczniki z serwera i dzielą renderowanie w taki sposób, aby uniknąć długich zadań. Znaczniki renderowane przez klienta są natomiast obsługiwane jako jedno monolityczne zadanie, które oprócz wartości INP może wpływać na dane o czasie reagowania stron, takie jak całkowity czas blokowania (TBT) lub opóźnienie przy pierwszym działaniu (FID).

Rozwiązanie problemu w takim przypadku zależy od odpowiedzi na pytanie: Czy istnieje jakiś powód, dla którego serwer nie może dostarczyć znaczników strony, zamiast renderować ją po stronie klienta? Jeśli odpowiedź na to pytanie brzmi „nie”, w miarę możliwości należy wziąć pod uwagę renderowanie po stronie serwera (SSR) lub znaczniki generowane statycznie, ponieważ pomoże to skanerowi w wykryciu i opportunistycznym pobrać ważne zasoby z wyprzedzeniem.

Jeśli Twoja strona wymaga JavaScriptu, aby dołączyć funkcje do niektórych części znaczników, możesz to zrobić za pomocą SSR za pomocą waniliowego JavaScriptu lub nawodnienia, aby wykorzystać zalety obu formatów.

Skaner wstępnego wczytywania może Ci pomóc

Skaner wstępnego wczytywania to wysoce skuteczna optymalizacja przeglądarki, która pomaga szybciej wczytywać strony podczas uruchamiania. Dzięki unikaniu wzorców, które uniemożliwiają mu dotarcie do ważnych zasobów z wyprzedzeniem, nie tylko ułatwiasz sobie programowanie, ale także zapewniasz lepsze wrażenia użytkowników, co z kolei przekłada się na lepsze wyniki w zakresie wielu danych, w tym niektórych podstawowych wskaźników internetowych.

Oto kilka rzeczy, o których warto pamiętać w tym poście:

  • Skaner wstępnego wczytywania przeglądarki to dodatkowy parser HTML, który skanuje przed serwerem głównym, jeśli jest zablokowany w celu znalezienia zasobów, które może pobrać szybciej.
  • Skaner wstępnego wczytywania nie może wykryć zasobów, których nie ma w znacznikach dostarczonych przez serwer w ramach wstępnego żądania nawigacji. Problemy ze skanerem wstępnego wczytywania mogą obejmować między innymi:
    • Wstawianie w modelu DOM zasobów, takich jak skrypty, obrazy, arkusze stylów czy inne elementy, które warto umieścić we wstępnym ładunku znaczników pochodzącym z serwera.
    • Leniwe ładowanie obrazów w części strony widocznej na ekranie lub elementów iframe przy użyciu rozwiązania JavaScript.
    • Renderowanie na kliencie znaczników, które mogą zawierać odwołania do zasobów podrzędnych dokumentów, przy użyciu JavaScriptu.
  • Skaner wstępnego wczytywania skanuje tylko kod HTML. Nie sprawdza zawartości innych zasobów – w szczególności CSS – które mogą zawierać odwołania do ważnych zasobów, w tym do kandydatów LCP.

Jeśli z jakiegokolwiek powodu nie możesz uniknąć wzorca, który negatywnie wpływa na zdolność skanera do przyspieszania wczytywania strony, skorzystaj z wskazówek dotyczących zasobów rel=preload. Jeśli używasz rel=preload, przetestuj je w narzędziach laboratoryjnych, aby się upewnić, że przynosi to oczekiwane rezultaty. Nie wczytuj wstępnie zbyt wielu zasobów, ponieważ gdy ustalisz priorytety, nic się nie uda.

Zasoby

Baner powitalny ze zbioru Unsplash, autor: Mohammad Rahmani .