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ć.

Jednym z pomijanych aspektów optymalizacji szybkości strony jest znajomość wewnętrznej budowy przeglądarki. Przeglądarki przeprowadzają pewne optymalizacje poprawiające wydajność w sposób, którego my jako programiści nie możemy tego robić, 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.

Schemat działania parsowania 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 renderowanie jest blokowane, aby zapobiec przebłysku niesformatowanej treści (FOUC), czyli sytuacji, gdy niesformatowana wersja strony może być krótko widoczna, zanim zostaną do niej zastosowane style.

Strona główna web.dev bez stylizacji (po lewej) i ze stylizacją (po prawej).
Rys. 2: symulowany przykład FOUC. Po lewej znajduje się pierwsza strona web.dev bez stylów. Po prawej stronie znajduje się ta sama strona ze stylami. Brak stylu może wystąpić w wyniku Flash, 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. Dlatego zwykło się wczytywać kod JavaScript na końcu dokumentu, aby efekty zablokowanego analizowania i renderowania były marginalne.

Z tych powodów przeglądarka powinna blokować zarówno analizowanie, jak i renderowanie. Blokowanie któregokolwiek z tych ważnych kroków jest jednak 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. Schemat pokazujący, jak skaner wstępnego wczytania działa równolegle z głównym parsowaniem kodu HTML w celu spekulatywnego wczytania zasobów. W tym przypadku główny parsujący HTML jest zablokowany, ponieważ wczytuje i przetwarza CSS, zanim zacznie przetwarzać znaczniki obrazu w elemencie <body>. Skaner wstępnego wczytania może jednak zajrzeć do nieprzetworzonego znacznika, aby znaleźć zasób obrazu i rozpocząć jego wczytywanie, zanim odblokowany zostanie główny parsujący 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 dla żądań, aby dowiedzieć się, gdzie działa skaner wstępnego ładowania.

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 sieciowy strony internetowej uruchomiony 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 działa 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 WebPageTest przedstawiający stronę internetową uruchomioną w Chrome na urządzeniu mobilnym przez symulowane połączenie 3G. Strona zawiera 1 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.

Oto, co się tutaj stało:

  1. W 0 sekundzie wysyłany jest dokument główny.
  2. Po 1, 4 sekundy pojawia się pierwszy bajt żądania nawigacji.
  3. W 2, 0 sekundy są wysyłane żądania CSS i obraz.
  4. Ponieważ parsowanie jest zablokowane, wczytywanie arkusza stylów i wbudowany kod JavaScript, który wstrzykuje kod async, pojawia się po tym arkuszu stylów po 2,6 sekundy, funkcja tego kodu nie jest dostępna od razu.

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ę stanie, jeśli zamiast wstrzykiwania skryptu do DOM-u użyjesz zwykłego tagu <script> z atrybutem async?

<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. Kaskadowy wykres kaskadowy WebPageTest przedstawiający stronę internetową uruchomioną 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.

Możesz mieć pokusę, by zasugerować, że te problemy można rozwiązać, używając 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. Kaskadowy wykres kaskadowy WebPageTest przedstawiający stronę internetową uruchomioną 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 „poprawek” tutaj pojawia się nowy problem, ale pojawia się nowy problem: skrypt async w 2 pierwszych wersjach demonstracyjnych (mimo załadowania w <head>) jest wczytywany „Niski” a arkusz stylów ma wartość „Najwyższa” . W ostatniej wersji demonstracyjnej, w której skrypt async jest wstępnie wczytywany, arkusz stylów jest nadal wczytywany na poziomie „Najwyższa” ale priorytet skryptu został zwiększony do „Wysoki”.

Gdy priorytet zasobu wzrośnie, przeglądarka przydzieli mu więcej przepustowości. 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 za pomocą 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.

Może to powodować potencjalne problemy z wykrywalnością zasobów w przypadku skanera wstępnego ładowania i może niepotrzebnie wydłużać czas potrzebny na znalezienie odwołania do obrazu, jego pobranie, dekodowanie i wyświetlenie. Weźmy na przykład ten znacznik 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.
Ryc. 8. Wykres kaskadowy sieci WebPageTest strony internetowej uruchomionej w Chrome na urządzeniu mobilnym z symulowanym połączeniem 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 kaskady 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. Kaskadowy wykres kaskadowy WebPageTest przedstawiający stronę internetową uruchomioną 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, które mogą wymagać pobierania obrazów odwołujących się do właściwości background-image.

Podobnie jak w przypadku HTML, przeglądarki przetwarzają kod CSS w swój własny model obiektów, 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. Sieciowy wykres kaskadowy 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 strony internetowej uruchomionej w Chrome na urządzeniu mobilnym z symulowanym połączeniem 3G. Kandidatem na LCP strony jest element z właściwością CSS background-image (wiersz 3). Wskazówka rel=preload pomaga przeglądarce wykryć obraz około 250 ms 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. Jest ona widoczna w dokumencie i wczytuje się natychmiast. Ma on jednak istotne wady:

  • Jeśli nie przechowujesz w pamięci podręcznej kodu HTML (a nie możesz tego zrobić, gdy odpowiedź HTML jest dynamiczna), zaszyte zasoby nigdy nie są przechowywane 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 przechowywać w pamięci podręcznej 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 wykorzystywać w całym punkcie początkowym.
  • Jeśli wstawiasz zbyt wiele elementów, skanowanie wstępne opóźni się, ponieważ wykrywanie zasobów w dalszej części dokumentu będzie trwało 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 używa też 4 czcionek internetowych, które są żądane jako osobne pliki z zasobu 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 jest w odpowiednim czasie wykrywany przez skaner wstępnego wczytania.
Rys. 12. Sieciowy wykres kaskadowy 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 jest on wykrywany przez skaner wstępnego wczytania, ponieważ czcionki i pliki CSS wymagane do wczytania strony znajdują się w oddzielnych zasobach, co nie opóźnia działania skanera wstępnego wczytania.

Co się stanie, jeśli CSS iwszystkie czcionki są wbudowane jako zasoby base64?

Wykres kaskadowy sieci WebPageTest strony z zewnętrznym plikiem CSS zawierającym odniesienia do 4 czcionek. Skaner wstępnego wczytywania ma znaczne opóźnienie w wykryciu obrazu LCP .
Rys. 13. Sieciowy wykres kaskadowy 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 wstawienie kodu inline negatywnie wpływa na LCP, a także ogólną wydajność. Wersja strony, która nie ma w tekście żadnego elementu wbudowanego, obrazuje obraz LCP w ciągu ok.3,5 sekundy. Strona, która wyświetla wszystko w ramce, nie renderuje obrazu LCP do ponad 7 sekund.

W tym przypadku chodzi o coś więcej niż tylko skaner wstępnego wczytania. Wbudowanie czcionek nie jest dobrym rozwiązaniem, ponieważ base64 nie jest wydajnym formatem dla zasobów binarnych. Kolejnym czynnikiem jest to, że zewnętrzne zasoby czcionek nie są pobierane, chyba że zostaną uznane za niezbędne 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ć? Jasne. 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.

Bardzo ostrożnie podchodź do wstawiania elementów 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. 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 wątpliwości, że JavaScript ma wpływ na szybkość wczytywania strony. Deweloperzy nie tylko polegają na niej, aby zapewnić interaktywność, ale też na samo dostarczanie treści. Pod wieloma względami zapewnia to deweloperom lepsze wrażenia. ale korzyści dla programistó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.
Ryc. 14. Wykres kaskadowy sieci WebPageTest strony internetowej renderowanej po stronie klienta, która działa w Chrome na urządzeniu mobilnym z symulowanym połączeniem 3G. Treści są zawarte w języku JavaScript i wykorzystywane do renderowania, więc zasób obrazu w znacznikach renderowanych przez klienta jest ukryty przed skanerem wstępnego wczytywania. Odpowiednią wersję z renderowaniem po stronie serwera przedstawia 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 znaczniki strony nie mogą być dostarczane przez serwer, a zamiast tego są renderowane po stronie klienta? 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.

Jak korzystać z skanera wstępnego

Skaner wstępnego wczytywania to bardzo skuteczna optymalizacja przeglądarki, która przyspiesza wczytywanie stron podczas uruchamiania. Unikając wzorców, które uniemożliwiałyby poznanie 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 podsumowanie tego posta:

  • 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 załadowania może być ukryty między innymi z następujących powodów:
    • Wstrzykiwanie zasobów do DOM za pomocą JavaScriptu, np. skryptów, obrazów, arkuszy stylów lub innych elementów, które lepiej byłoby umieścić w pierwotnym ładunku znaczników ze strony 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 załadowania skanuje tylko kod HTML. Nie sprawdza zawartości innych zasobów, zwłaszcza CSS, które mogą zawierać odniesienia do ważnych zasobów, w tym kandydatów do 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 narzędzia rel=preload, przetestuj je w narzędziach laboratoryjnych, aby upewnić się, że działają zgodnie z oczekiwaniami. 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, autor: Mohammad Rahmani .