Nie walcz ze skanerem wstępnego wczytywania przeglądarki

Dowiedz się, czym jest skaner wstępnego wczytywania w przeglądarce, jak zwiększa wydajność i jak zabezpieczyć się przed utratą ruchu.

Jednym z pomijanych aspektów optymalizacji szybkości strony jest znajomość wewnętrznej budowy przeglądarki. Przeglądarki wprowadzają pewne optymalizacje, aby poprawić wydajność w sposób, którego my, jako deweloperzy, nie możemy wykorzystać, ale tylko wtedy, gdy te optymalizacje nie zostaną przypadkowo zablokowane.

Jedną z optymalizacji przeglądarki wewnętrznej, którą warto poznać, jest skaner wstępnego ładowania przeglądarki. Z tego artykułu dowiesz się, jak działa skaner wstępnego wczytywania i jak uniknąć problemów z jego działaniem.

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 trwa do momentu, gdy parsowanie zostanie wstrzymane po znalezieniu zasobu blokującego, takiego jak wczytana szata wczytana za pomocą elementu <link> lub skrypt wczytany za pomocą elementu <script> bez atrybutu async lub defer.

Schemat działania parsowania HTML
Ryc. 1. Diagram przedstawiający sposób blokowania głównego modułu parsowania HTML w przeglądarce. 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 błyskawicznemu wyświetlaniu treści bez stylów (FOUC), czyli sytuacji, w której na krótko widoczna jest wersja strony bez stylów, zanim zostaną one zastosowane.

Strona główna web.dev bez stylu (po lewej) ze stylem (po prawej).
Rysunek 2. Symulowany przykład funkcji OCR. Po lewej stronie znajduje się strona główna web.dev bez stylów. Po prawej ta sama strona z zastosowanymi 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 też analizowanie i renderowanie strony, gdy napotyka elementy <script> bez atrybutu defer lub async.

Dzieje się tak, ponieważ przeglądarka nie może mieć pewności, czy dany skrypt zmodyfikuje DOM, gdy główny parsarz HTML nadal wykonuje swoje zadanie. Właśnie dlatego tak powszechną praktyką jest ładowanie kodu JavaScript na końcu dokumentu, tak by skutki zablokowania analizy 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.

Schemat pokazujący działanie głównego analizatora HTML (po lewej) i skanera wstępnego ładowania (po prawej), który jest dodatkowym analizatorem 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. Tutaj główny parsujący HTML jest zablokowany, ponieważ wczytuje i przetwarza CSS, zanim zacznie przetwarzać znaczniki obrazu w elemencie <body>. Skaner wstępnego wczytywania może jednak zajrzeć do nieprzetworzonego znacznika, aby znaleźć zasób obrazu i rozpocząć jego wczytywanie, zanim zostanie odblokowany główny parsujący HTML.

Rola skanera wstępnego jest spekulacyjna, co oznacza, że skaner sprawdza surowy znacznik, aby znaleźć zasoby do pobrania, zanim główny parsujący HTML je odkryje.

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

Skaner wstępnego wczytywania istnieje z powodu zablokowanego renderowania i analizowania. 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.

Weźmy na przykład tę stronę z tekstem i obrazami z wykorzystaniem arkusza stylów. Ponieważ pliki CSS blokują zarówno renderowanie, jak i analizę, wprowadzasz sztuczne opóźnienie o 2 sekundy dla arkusza stylów za pomocą usługi proxy. Dzięki temu łatwiej jest sprawdzić w splacie sieciowym, kiedy działa skaner wstępnego ładowania.

Wykres sieci WebPageTest pokazuje sztuczne opóźnienie o 2 sekundy narzucone 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 wczytywanie skryptu zostaje sztucznie opóźnione przez serwer proxy o 2 sekundy, obraz znajdujący się później w pliku danych znaczników jest wykrywany przez skaner wstępnego wczytania.

Jak widać na wykresie kaskadowym, skaner wstępnego załadowania wykrywa element <img> nawet wtedy, gdy renderowanie i analiza dokumentu są zablokowane. Bez tej optymalizacji przeglądarka nie może pobierać danych w okresie blokowania, a więcej żądań zasobów będzie się pojawiać kolejno, a nie równocześnie.

Po przykładzie zabawki przyjrzyjmy się teraz prawdziwym wzorom, w których przypadku skaner wstępnego ładowania może zostać pokonany, oraz temu, jak można to naprawić.

Wstrzyknięto async skryptu

Załóżmy, że w pliku <head> masz kod HTML, który zawiera kod JavaScript wbudowany w tekst, np. taki:

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

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

Wstrzyknięte skrypty są domyślnie async, więc po wstrzyknięciu skrypt będzie zachowywać się tak, jakby miał 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. Wykres kaskadowy sieci WebPageTest strony internetowej uruchomionej w Chrome na urządzeniu mobilnym z symulowanym połączeniem 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.

Opiszmy to, co się tutaj wydarzyło:

  1. W 0 sekundzie wysyłany jest dokument główny.
  2. W 1,4 sekundy dociera 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 rozwiązanie, ponieważ żądanie skryptu jest wysyłane dopiero po zakończeniu pobierania arkusza stylów. Dzięki temu skrypt nie zostanie uruchomiony od razu. Z drugiej strony, element <img> jest dostępny w znacznikach dostarczonych przez serwer, więc jest wykrywany przez skaner wstępnego wczytania.

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 wynik:

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 kaskady sieci WebPageTest strony internetowej uruchomionej w Chrome na urządzeniu mobilnym z symulowanym połączeniem 3G. Strona zawiera 1 arkusz stylów i 1 element async <script>. Skaner wstępnego wczytywania wykrywa skrypt na etapie blokowania renderowania i wczytuje go równolegle z arkuszy CSS.

Możesz mieć pokusę, by zasugerować, że te problemy można rozwiązać, używając rel=preload. To na pewno zadziała, ale może mieć pewne skutki uboczne. Po co używać elementu rel=preload do rozwiązania problemu, którego można uniknąć, nie wstrzykując elementu <script> do DOM?

Kaskada WebPageTest pokazująca, jak wskazówka zasobu rel=preload jest używana do promowania wykrywania asynchronicznie wstrzykniętego skryptu, ale w sposób, który 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 pojedynczy plik stylesheet i wstrzyknięty skrypt async, ale skrypt async jest wstępnie wczytany, aby zapewnić jego wcześniejsze wykrycie.

Wczytywanie z wyprzedzeniem „rozwiązuje” ten problem, ale powoduje pojawienie się nowego: skrypt async w pierwszych 2 demonstracjach – mimo że jest wczytywany w ramach <head> – jest wczytywany z priorytetem „Niski”, podczas gdy arkusz stylów jest wczytywany z priorytetem „Najwyższy”. W ostatnim pokazie, w którym skrypt async jest wstępnie wczytany, wczytywanie arkusza stylów nadal ma priorytet „Najwyższy”, ale priorytet skryptu został podwyższony do „Wysoki”.

Gdy priorytet zasobu wzrośnie, przeglądarka przydzieli mu więcej przepustowości. Oznacza to, że nawet jeśli szata ma najwyższy priorytet, podwyższony priorytet skryptu może spowodować konflikt przepustowości. Może to być spowodowane wolnym połączeniem lub dużymi zasobami.

Odpowiedź jest prosta: jeśli skrypt jest potrzebny podczas uruchamiania, nie pokonuj skanera wstępnego ładowania, wstrzykując go do DOM. W razie potrzeby eksperymentuj z umieszczaniem elementów <script> oraz z atrybutami takimi jak deferasync.

Leniwe ładowanie z użyciem JavaScriptu

Łagodne wczytywanie to świetna metoda oszczędzania danych, która jest często stosowana w przypadku 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 zostanie przewinięty do widoku, opóźniony ładowacz usunie prefiks data-, co oznacza, że w poprzednim przykładzie data-src stanie się 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 wczytania nie odczytuje atrybutu data-src w taki sam sposób jak atrybutu src (lub srcset), więc odniesienie do obrazu nie zostanie wcześniej wykryte. Co gorsza, obraz jest wczytywany dopiero po pobraniu, skompilowaniu i wykonywaniu kodu JavaScript.

Wykres sieci WebPageTest pokazujący, jak obraz wczytywany z opóźnieniem, który jest widoczny w widoku podczas uruchamiania, jest koniecznie opóźniony, ponieważ skaner wstępnego wczytania przeglądarki nie może znaleźć zasobu obrazu i ładuje się dopiero wtedy, gdy zostanie załadowany JavaScript wymagany do wczytywania z opóźnieniem. obraz jest odkrywany 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 z opóźnieniem, mimo że jest widoczny w widocznym obszarze podczas uruchamiania. To uniemożliwia działanie skanera 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 to być element kwalifikujący się 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">

Jest to optymalny wzór dla obrazów, które są widoczne w widoku podczas uruchamiania, ponieważ skaner wstępnego ładowania szybciej wykryje i pobierze zasób obrazów.

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 aplikacji WebPageTest przedstawiający stronę internetową w Chrome na urządzeniu mobilnym przez symulowane połączenie 3G. Skaner wstępnego załadowania wykrywa zasób obrazu przed rozpoczęciem wczytywania kodu CSS i JavaScriptu, co daje przeglądarce przewagę w wczytywaniu.

W tym uproszczonym przykładzie wynik to poprawa LCP o 100 ms przy wolnym połączeniu. 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 do LCP mogą konkurować o przepustowość z wielkimi zasobami, dlatego takie optymalizacje stają się coraz ważniejsze.

Obrazy tła w kodzie CSS

Pamiętaj, że skaner wstępnego załadowania przeglądarki skanuje oznaczenia. 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 podczas tworzenia obiektu CSSOM zostaną wykryte zasoby zewnętrzne, są one żądane w momencie ich wykrycia, a nie przez skaner wstępnego ładowania.

Załóżmy, że kandydat na LCP na stronie to element z właściwością CSS background-image. Podczas wczytywania zasobów:

Wykres osi czasu sieci WebPageTest przedstawiający stronę z elementem LCP wczytywanym z arkusza CSS za pomocą właściwości background-image. 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ą w Chrome na urządzeniu mobilnym przez symulowane połączenie 3G. Identyfikator LCP strony to element z właściwością CSS background-image (wiersz 3). Przetwarzanie żądanego obrazu rozpoczyna się dopiero po znalezieniu go przez parsujący CSS.

W takim przypadku skaner wstępnego ładowania nie został tak naprawdę pokonany, tylko nie był używany. Mimo to, jeśli kandydat na element LCP na stronie pochodzi z elementu background-image usługi CSS, warto go wstępnie załadować:

<!-- 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 sieci WebPageTest pokazujący obraz tła CSS (który jest kandydatem na LCP) wczytywany znacznie wcześniej dzięki zastosowaniu wskazówki rel=preload. Czas LCP skraca 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. Identyfikator LCP strony to 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 wskazówki.

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. Dzięki tagowi <img> możesz lepiej kontrolować wczytywanie obrazu odpowiedniego dla widoku, a jednocześnie umożliwić skanowanie go przez skaner wstępnego wczytywania.

Wstawianie zbyt wielu zasobów

Wstawianie to umieszczanie zasobu w kodzie HTML. Możesz wstawiać w treści style w elementach <style>, skrypty w elementach <script> i praktycznie dowolne inne zasoby za pomocą kodowania base64.

Wstawianie zasobów może być szybsze niż ich pobieranie, ponieważ nie jest wysyłane osobne żądanie. Znajdziesz ją w dokumencie i błyskawicznie wczytywana. Ma on jednak istotne wady:

  • 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ż zaszyte zasoby nie mogą być użyte ponownie.
  • Nawet jeśli możesz zapisać kod HTML w pamięci podręcznej, zasoby wbudowane nie są współdzielone między dokumentami. Ogranicza to skuteczność pamięci podręcznej 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 wstawisz zbyt wiele treści, skanowanie wstępne opóźni się, ponieważ wykrywanie zasobów w dalszej części dokumentu zajmie więcej czasu.

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

Wykres kaskady sieci WebPageTest strony z zewnętrznym plikiem CSS zawierającym odniesienia do 4 czcionek. Obraz kandydujący do LCP zostanie w odpowiednim czasie wykryty przez skaner wstępnego ładowania.
Rys. 12. Wykres kaskadowy sieci WebPageTest strony internetowej uruchomionej w Chrome na urządzeniu mobilnym z symulowanym połączeniem 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 kaskady sieci WebPageTest strony z zewnętrznym plikiem CSS zawierającym odniesienia do 4 fontów. Skaner wstępnego wczytywania ma znaczne opóźnienie w wykryciu obrazu LCP .
Rys. 13. Wykres kaskadowy sieci WebPageTest przedstawiający stronę internetową w Chrome na urządzeniu mobilnym przez symulowane połączenie 3G. Kandydat na LCP strony to obraz wczytywany z elementu <img>, ale wstawienie w elementie `` powoduje, że skanowanie wstępne nie może wykryć obrazu, dopóki nie zostaną całkowicie pobrane wszystkie zasoby czcionek.

W tym przykładzie wstawienie kodu inline negatywnie wpływa na LCP, a także ogólną wydajność. Wersja strony, która nie zawiera żadnych elementów wstawianych, renderuje obraz LCP w około 3,5 sekundy. Strona, która wyświetla wszystko w linii, nie renderuje obrazu LCP do ponad 7 sekund.

Nie chodzi tylko o skaner wstępnego wczytywania. 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. Gdy te czcionki są wstawiane w formacie base64, są pobierane niezależnie od tego, czy są potrzebne na bieżącej stronie.

Czy w takim przypadku załadowanie wstępne może pomóc? 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 wstawione, FCP wynosi około 5,8 sekund.

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. Wstawiaj jak najmniej elementów, ponieważ zbyt duża liczba wstawionych elementów może spowodować problemy.

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. W pewnym sensie sprzyja to deweloperom, ale korzyści dla nich nie zawsze przekładają się na korzyści dla użytkowników.

Jednym z wzorów, który może uniemożliwić działanie skanera wstępnego wczytywania, jest renderowanie znaczników za pomocą kodu JavaScript po stronie klienta:

Sieć WebPageTest w postaci wykresu kaskadowego przedstawiającego podstawową stronę z obrazami i tekstem renderowanym całkowicie po stronie klienta w JavaScript. Markowanie jest zawarte w JavaScript, więc skaner wstępnego wczytania nie może wykryć żadnych zasobów. Wszystkie zasoby są dodatkowo opóźnione z powodu dodatkowego czasu potrzebnego na przetwarzanie i przesyłanie danych przez sieć, który wymagają frameworki 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ść jest zawarta w JavaScript i korzysta z ramy do renderowania, dlatego zasób obrazów w oznaczeniu renderowanym po stronie klienta jest ukryty przed skanerem wstępnego ładowania. Odpowiednik renderowany przez serwer jest przedstawiony na Rys. 9.

Gdy dane znaczników są zawarte w JavaScript i w pełni renderowane przez niego w przeglądarce, wszystkie zasoby w tym znaczniku są w praktyce niewidoczne dla skanera wstępnego. 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.

To trochę odbiega od tematu tego artykułu, ale efekty renderowania znaczników na kliencie wykraczają daleko poza pokonywaniem skanera wstępnego ładowania. Po pierwsze, wprowadzenie JavaScriptu do obsługi funkcji, która go nie wymaga, powoduje niepotrzebne przetwarzanie, co może mieć wpływ na czas od interakcji do kolejnego wyrenderowania (INP). Renderowanie bardzo dużych ilości znaczników na kliencie powoduje dłuższe zadania niż w przypadku takiej samej ilości znaczników wysyłanych przez serwer. Powodem tego, poza dodatkowym przetwarzaniem wymaganym przez JavaScript, jest to, że przeglądarki przesyłają znaczniki ze serwera i dzielą renderowanie na części w taki sposób, aby ograniczać czas wykonywania długich zadań. Z drugiej strony znaczniki renderowane po stronie klienta są obsługiwane jako pojedyncze, monolityczne zadanie, które może wpływać na 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ź na to pytanie brzmi „nie”, należy rozważyć renderowanie po stronie serwera (SSR) lub generowanie znaczników statycznych, o ile to możliwe, ponieważ pomoże to skanerowi w poprzednim wykrywaniu i pobieraniu ważnych zasobów.

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 Ci to korzystać z obu rozwiązań.

Jak korzystać z skanera wstępnego

Skaner wstępnego wczytywania to bardzo skuteczna optymalizacja przeglądarki, która pomaga szybciej wczytywać strony 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 wskaźników, w tym niektórych wskaźników internetowych.

Oto najważniejsze informacje z tego posta:

  • Skaner wstępnego wczytywania przeglądarki to dodatkowy parsujący HTML, który skanuje przed głównym, jeśli jest zablokowany, aby optymistycznie wykrywać zasoby, 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ć zniwelowany między innymi przez:
    • 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 obciążeniu znaczników ze strony serwera.
    • wczytywanie z opóźnieniem obrazów i iframe znajdujących się powyżej pola widzenia 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ąć wzoru, który negatywnie wpływa na zdolność skanera wstępnego wczytywania do przyspieszania wczytywania, skorzystaj z wskazówek dotyczących 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 wczytuj też zbyt wielu zasobów, ponieważ jeśli wszystko będzie miało najwyższy priorytet, żadne z nich nie będzie miało priorytetu.

Zasoby

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