Bekämpfe den Vorablade-Scanner des Browsers nicht

Hier erfahren Sie, was der Browser Preload Scanner ist, wie er die Leistung verbessert und wie Sie ihm aus dem Weg gehen können.

Ein Aspekt bei der Optimierung der Seitengeschwindigkeit ist es, sich mit den internen Strukturen von Browsern vertraut zu machen. Browser führen bestimmte Optimierungen durch, um die Leistung auf eine Weise zu verbessern, wie wir das als Entwickler nicht können – aber nur, solange diese Optimierungen nicht versehentlich verhindert werden.

Eine interne Browseroptimierung, die Sie kennen sollten, ist der Browser-Preload-Scanner. In diesem Beitrag erfahren Sie, wie der Scanner zum Vorabladen funktioniert – und, noch wichtiger, wie Sie verhindern können, dass er in die Quere kommt.

Was ist ein Preload-Scanner?

Jeder Browser hat einen primären HTML-Parser, der unbearbeitetes Markup tokenisiert und in ein Objektmodell verarbeitet. Das alles geht fröhlich weiter, bis der Parser eine blockierende Ressource findet, z. B. ein Stylesheet, das mit einem <link>-Element geladen ist, oder ein Script, das mit einem <script>-Element ohne async- oder defer-Attribut geladen wurde.

HTML-Parser-Diagramm.
Abb. 1:Ein Diagramm, das zeigt, wie der primäre HTML-Parser des Browsers blockiert werden kann. In diesem Fall trifft der Parser auf ein <link>-Element für eine externe CSS-Datei, das den Browser daran hindert, den Rest des Dokuments zu parsen oder überhaupt zu rendern. Dies hindert den Browser daran, bis das CSS heruntergeladen und geparst wurde.

Bei CSS-Dateien wird das Rendering blockiert, um ein Flash of Unstyled Content (FOUC) zu verhindern. Dabei wird eine unformatierte Version einer Seite kurz angezeigt, bevor Stile darauf angewendet werden.

Die Startseite von web.dev ohne Stil (links) und mit Stil (rechts).
Abb. 2: Ein simuliertes Beispiel für FOUC. Links sehen Sie die Startseite von web.dev ohne Stile. Rechts ist dieselbe Seite mit angewendeten Stilen zu sehen. Dieser Zustand kann im Flash-Format auftreten, wenn der Browser das Rendern nicht blockiert, während ein Stylesheet heruntergeladen und verarbeitet wird.

Der Browser blockiert auch das Parsen und Rendern der Seite, wenn <script>-Elemente ohne defer- oder async-Attribut gefunden werden.

Der Grund dafür ist, dass der Browser nicht mit Sicherheit wissen kann, ob ein bestimmtes Skript das DOM ändert, während der primäre HTML-Parser noch seine Aufgabe ausführt. Aus diesem Grund wird der JavaScript-Code häufig am Ende des Dokuments geladen, damit die Auswirkungen eines blockierten Parsens und Renderns geringfügig werden.

Das sind gute Gründe dafür, dass der Browser sowohl das Parsen als auch das Rendern blockieren sollte. Es ist jedoch nicht wünschenswert, einen dieser wichtigen Schritte zu blockieren, da dies die Suche nach anderen wichtigen Ressourcen verzögern kann. Glücklicherweise versuchen die Browser, diese Probleme mithilfe eines sekundären HTML-Parsers, dem Preload Scanner, zu minimieren.

Ein Diagramm des primären HTML-Parsers (links) und des Preloading-Scanners (rechts), dem sekundären HTML-Parser.
Abb. 3:Ein Diagramm, das zeigt, wie der Preload-Scanner parallel zum primären HTML-Parser funktioniert, um Assets spekulativ zu laden. Hier wird der primäre HTML-Parser blockiert, während er CSS lädt und verarbeitet, bevor er mit der Verarbeitung des Bild-Markups im <body>-Element beginnen kann. Der Vorabladescanner kann jedoch im Roh-Markup nach dieser Bildressource suchen und mit dem Laden beginnen, bevor die Blockierung des primären HTML-Parsers aufgehoben wird.

Die Rolle eines Preload-Scanners ist spekulativ. Das bedeutet, dass er Roh-Markup untersucht, um Ressourcen zu finden, die opportunistisch abgerufen werden können, bevor der primäre HTML-Parser sie sonst finden würde.

Prüfen, ob der Preloader funktioniert

Der Preload-Scanner ist vorhanden, weil das Rendering und Parsen blockiert sind. Wenn diese beiden Leistungsprobleme nie existieren würden, wäre der Scanner zum Vorabladen nicht sehr nützlich. Ob eine Webseite vom Preload-Scanner profitiert, hängt von diesen Blockierphänomenen ab. Dazu können Sie eine künstliche Verzögerung für Anfragen einleiten, um herauszufinden, wo der Scanner zum Vorabladen arbeitet.

Sehen Sie sich diese Seite mit einfachem Text und Bildern mit einem Stylesheet als Beispiel an. Da CSS-Dateien sowohl das Rendern als auch das Parsen blockieren, kommt es für das Stylesheet über einen Proxy-Dienst zu einer künstlichen Verzögerung von zwei Sekunden. Durch diese Verzögerung ist es in der Netzwerkabfolge einfacher zu erkennen, wo der Preload-Scanner arbeitet.

Im WebPageTest-Netzwerk-Wasserfalldiagramm wird eine künstliche Verzögerung von 2 Sekunden für das Stylesheet dargestellt.
Abb. 4:Ein WebPageTest-Wasserfalldiagramm mit einer Webseite wird in Chrome auf einem Mobilgerät über eine simulierte 3G-Verbindung ausgeführt. Obwohl das Stylesheet über einen Proxy vor dem Ladevorgang zwei Sekunden verzögert wird, wird das Bild, das sich später in der Markup-Nutzlast befindet, vom Preload-Scanner erkannt.

Wie Sie in der Ablaufgrafik sehen, erkennt der Vorab-Scanner das <img>-Element auch dann, wenn das Rendering und das Parsen des Dokuments blockiert sind. Ohne diese Optimierung kann der Browser während der Blockierungsphase keine Elemente nach Möglichkeit abrufen und es würden mehr Ressourcenanfragen nacheinander und nicht gleichzeitig ausgeführt.

Nachdem wir uns dieses Beispiel angesehen haben, sehen wir uns einige reale Muster an, bei denen der Preloader-Scanner ausgetrickst werden kann, und was dagegen unternommen werden kann.

async Script eingefügt

Angenommen, Ihr <head> enthält HTML-Code mit Inline-JavaScript:

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

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

Eingefügte Skripts sind standardmäßig async. Wenn dieses Script also eingeschleust wird, verhält es sich so, als würde das async-Attribut darauf angewendet werden. Das bedeutet, dass sie so schnell wie möglich ausgeführt wird und das Rendering nicht blockiert. Klingt optimal, oder? Wenn Sie jedoch davon ausgehen, dass dieses Inline-<script> nach einem <link>-Element kommt, das eine externe CSS-Datei lädt, erhalten Sie ein nicht optimales Ergebnis:

Dieses WebPageTest-Diagramm zeigt den Vorabladescan, der beim Einschleusen eines Skripts abgebrochen wird.
Abb. 5:Ein WebPageTest-Netzwerk-Wasserfalldiagramm mit einer Webseite, das in Chrome auf einem Mobilgerät über eine simulierte 3G-Verbindung ausgeführt wird. Die Seite enthält ein einzelnes Stylesheet und ein eingefügtes async-Script. Der Scanner für das Vorabladen kann das Skript während der Blockierphase für das Rendering nicht erkennen, da es in den Client injiziert wird.

Fassen wir zusammen, was passiert ist:

  1. Nach 0 Sekunden wird das Hauptdokument angefordert.
  2. Nach 1,4 Sekunden wird das erste Byte der Navigationsanfrage empfangen.
  3. Nach 2 Sekunden werden das CSS und das Bild angefordert.
  4. Da der Parser das Laden des Stylesheets blockiert und das Inline-JavaScript, das das Skript async einfügt, kommt nach diesem Stylesheet nach 2,6 Sekunden, sodass die von diesem Skript bereitgestellten Funktionen nicht so schnell wie möglich verfügbar sind.

Dies ist nicht optimal, da die Anfrage für das Skript erst erfolgt, nachdem der Download des Stylesheets abgeschlossen ist. Dadurch wird die Ausführung des Scripts verzögert. Da das <img>-Element im Gegensatz dazu im vom Server bereitgestellten Markup sichtbar ist, wird es vom Preload-Scanner erkannt.

Was passiert, wenn Sie ein reguläres <script>-Tag mit dem Attribut async verwenden, anstatt das Skript in das DOM einzufügen?

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

Das Ergebnis:

Eine WebPageTest-Netzwerkabfolge, die zeigt, wie ein asynchrones Skript, das mithilfe des HTML-Skriptelements geladen wird, vom Scanner zum Vorabladen des Browsers immer noch erkannt wird, obwohl der primäre HTML-Parser des Browsers beim Herunterladen und Verarbeiten eines Stylesheets blockiert wird.
Abb. 6: Ein WebPageTest-Netzwerk-Wasserfalldiagramm mit einer Webseite, das in Chrome auf einem Mobilgerät über eine simulierte 3G-Verbindung ausgeführt wird. Die Seite enthält ein einzelnes Stylesheet und ein einzelnes async-<script>-Element. Der Scanner zum Vorabladen erkennt das Skript während der Blockierphase für das Rendering und lädt es gleichzeitig mit dem CSS.

Es kann verlockend sein, zu behaupten, dass diese Probleme mit rel=preload behoben werden könnten. Das würde sicher funktionieren, kann aber einige Nebenwirkungen mit sich bringen. Warum sollten Sie schließlich rel=preload verwenden, um ein Problem zu beheben, das sich vermeiden lässt, indem Sie kein <script>-Element in das DOM einschleusen?

Eine WebPageTest-Abfolge, die zeigt, wie der Ressourcenhinweis „rel=preload“ verwendet wird, um die Erkennung eines asynchron injizierten Skripts zu fördern – allerdings auf eine Weise, die unbeabsichtigte Nebeneffekte haben kann.
Abb. 7:Ein WebPageTest-Netzwerk-Wasserfalldiagramm mit einer Webseite, das in Chrome auf einem Mobilgerät über eine simulierte 3G-Verbindung ausgeführt wird. Die Seite enthält ein einzelnes Stylesheet und ein eingefügtes async-Skript. Das Skript async wird jedoch vorab geladen, damit es schneller erkannt wird.

„Korrekturen“ vorab laden hier tritt das Problem auf, führt jedoch zu einem neuen Problem: Das async-Skript in den ersten beiden Demos wird – obwohl es im <head> geladen wurde – mit einem niedrigen Wert geladen. Priorität hat, während das Stylesheet mit der höchsten Priorität geladen wird. Priorität haben. In der letzten Demo, in der das Skript async vorab geladen wurde, wird das Stylesheet immer noch mit der höchsten Einstellung geladen. aber die Priorität des Skripts wurde auf "Hoch" hochgestuft.

Wenn die Priorität einer Ressource erhöht wird, weist der Browser ihr mehr Bandbreite zu. Das bedeutet, dass die höhere Priorität des Skripts zu Bandbreitenkonflikten führen kann, auch wenn das Stylesheet die höchste Priorität hat. Dies kann bei langsamen Verbindungen oder bei sehr großen Ressourcen der Grund sein.

Die Antwort ist ganz einfach: Wenn beim Start ein Skript benötigt wird, sollten Sie den Preload-Scanner nicht durch Einschleusen in das DOM außer Kraft setzen. Experimentieren Sie bei Bedarf mit der Platzierung von <script>-Elementen sowie mit Attributen wie defer und async.

Lazy Loading mit JavaScript

Lazy Loading ist eine hervorragende Methode, um Daten zu sparen, die oft auf Bilder angewendet wird. Manchmal wird Lazy Loading jedoch fälschlicherweise auf Bilder angewendet, die sich sozusagen „above the fold“ befinden.

Dies birgt potenzielle Probleme bei der Auffindbarkeit von Ressourcen, wenn es um den Vorabladescanner geht. Außerdem kann es unnötig lange dauern, bis ein Verweis auf ein Bild erkannt, heruntergeladen, decodiert und präsentiert wird. Sehen wir uns dieses Bild-Markup als Beispiel an:

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

Die Verwendung des Präfixes data- ist ein gängiges Muster in JavaScript-gestützten Lazy Loader. Wenn in den Darstellungsbereich des Bildes gescrollt wird, entfernt der Lazy Loader das Präfix data-. Das bedeutet, dass im vorherigen Beispiel data-src zu src wird. Dadurch wird der Browser aufgefordert, die Ressource abzurufen.

Dieses Muster ist erst dann problematisch, wenn es auf Bilder angewendet wird, die sich beim Start im Darstellungsbereich befinden. Da der Vorabladescanner das data-src-Attribut nicht auf dieselbe Weise liest wie ein src- oder srcset-Attribut, wird der Bildverweis nicht früher erkannt. Schlimmer noch: Das Laden des Bildes wird erst nach dem Herunterladen, Kompilieren und Ausführen des Lazy Loader-JavaScripts verzögert.

Ein WebPageTest-Netzwerk-Wasserfalldiagramm, das zeigt, dass ein langsam geladenes Bild, das sich beim Start im Darstellungsbereich befindet, zwangsläufig verzögert ist, weil der Scanner für das Vorabladen des Browsers die Bildressource nicht finden kann und nur geladen wird, wenn das für Lazy Loading erforderliche JavaScript zum Ausführen des Ladevorgangs geladen wird. Das Bild wird viel später gefunden, als es sein sollte.
Abbildung 8: Ein WebPageTest-Netzwerk-Abfolgediagramm für eine Webseite, die in Chrome auf einem Mobilgerät über eine simulierte 3G-Verbindung ausgeführt wird. Die Bildressource wird unnötigerweise mit verzögertem Laden geladen, obwohl sie beim Start im Darstellungsbereich sichtbar ist. Dies macht den Preloader unzureichend und führt zu einer unnötigen Verzögerung.

Je nach Größe des Bildes, die auch von der Größe des Darstellungsbereichs abhängen kann, kann es ein Kandidatenelement für den Largest Contentful Paint (LCP) sein. Wenn der Preloader die Bildressource nicht spekulativ im Voraus abrufen kann – möglicherweise zu dem Zeitpunkt, an dem die Stylesheets der Seite das Rendering blockieren –, verschlechtert sich der LCP.

Die Lösung besteht darin, das Bild-Markup zu ändern:

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

Dies ist das optimale Muster für Bilder, die sich beim Start im Darstellungsbereich befinden, da der Scanner zum Vorabladen die Bildressource schneller erkennt und abruft.

Ein WebPageTest-Netzwerk-Wasserfalldiagramm, das ein Ladeszenario für ein Bild im Darstellungsbereich während des Starts zeigt Das Bild wird nicht verzögert geladen, das heißt, es ist nicht vom zu ladenden Script abhängig, was bedeutet, dass der Scanner vor dem Laden das Bild früher erkennen kann.
Abbildung 9: Ein WebPageTest-Netzwerk-Abfolgediagramm für eine Webseite, die in Chrome auf einem Mobilgerät über eine simulierte 3G-Verbindung ausgeführt wird. Der Scanner für Vorabladevorgänge erkennt die Bildressource, bevor CSS und JavaScript mit dem Laden beginnen. Dadurch hat der Browser einen Vorsprung beim Laden.

Das Ergebnis in diesem vereinfachten Beispiel ist eine Verbesserung des LCP um 100 Millisekunden bei einer langsamen Verbindung. Dies mag nicht nach einer großen Verbesserung erscheinen, aber wenn man bedenkt, dass es sich bei der Lösung um eine schnelle Markup-Korrektur handelt und dass die meisten Webseiten komplexer sind als diese Beispiele. Das bedeutet, dass LCP-Kandidaten möglicherweise mit vielen anderen Ressourcen um Bandbreite konkurrieren müssen, sodass Optimierungen wie diese immer wichtiger werden.

CSS-Hintergrundbilder

Denken Sie daran, dass der Scanner für das Vorabladen des Browsers das Markup scannt. Andere Ressourcentypen wie CSS werden nicht gescannt. Dabei werden möglicherweise Bilder abgerufen, auf die das Attribut background-image verweist.

Wie HTML wird CSS von Browsern in ein eigenes Objektmodell verarbeitet, das als CSSOM bezeichnet wird. Wenn beim Erstellen des CSSOM externe Ressourcen gefunden werden, werden diese Ressourcen zum Zeitpunkt der Erkennung angefordert und nicht vom Pre-Load-Scanner.

Der LCP-Kandidat Ihrer Seite ist ein Element mit der CSS-Eigenschaft background-image. Wenn Ressourcen geladen werden, geschieht Folgendes:

Ein WebPageTest-Netzwerk-Wasserfalldiagramm, das eine Seite mit einem LCP-Kandidaten zeigt, der über die Eigenschaft „background-image“ aus CSS geladen wurde. Da das Bild des LCP-Kandidaten zu einem Ressourcentyp gehört, den der Browser-Vorabladescanner nicht untersuchen kann, wird das Laden der Ressource bis zum Herunterladen und Verarbeiten des CSS-Codes verzögert, wodurch die Darstellungszeit des LCP-Kandidaten verzögert wird.
Abbildung 10: Ein WebPageTest-Netzwerk-Abfolgediagramm für eine Webseite, die in Chrome auf einem Mobilgerät über eine simulierte 3G-Verbindung ausgeführt wird. Der LCP-Kandidat der Seite ist ein Element mit der CSS-Eigenschaft background-image (Zeile 3). Das angeforderte Bild beginnt erst mit dem Abruf des Bildes, wenn es vom CSS-Parser gefunden wurde.

In diesem Fall ist der Scanner für das Vorabladen nicht so stark besiegt, sondern ohne Beteiligung. Wenn ein LCP-Kandidat auf der Seite jedoch von einer CSS-Eigenschaft background-image stammt, sollten Sie dieses Bild vorab laden:

<!-- 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">

Diese rel=preload-Hinweis ist klein, hilft dem Browser aber, das Bild früher zu finden als sonst:

Ein WebPageTest-Netzwerk-Wasserfalldiagramm, das ein CSS-Hintergrundbild (das LCP-Kandidaten) zeigt, das aufgrund eines rel=preload-Hinweises viel schneller geladen wird. Die LCP-Zeit verkürzt sich um etwa 250 Millisekunden.
Abb. 11: Ein WebPageTest-Netzwerk-Wasserfalldiagramm mit einer Webseite, das in Chrome auf einem Mobilgerät über eine simulierte 3G-Verbindung ausgeführt wird. Der LCP-Kandidat der Seite ist ein Element mit der CSS-Eigenschaft background-image (Zeile 3). Mit dem rel=preload-Hinweis kann der Browser das Bild etwa 250 Millisekunden früher erkennen als ohne den Hinweis.

Mit dem Hinweis rel=preload wird der LCP-Kandidat früher erkannt, wodurch die LCP-Zeit verringert wird. Mit diesem Hinweis lässt sich das Problem zwar beheben, aber vielleicht ist es besser, zu prüfen, ob der LCP-Kandidat für ein Bild aus CSS geladen werden muss. Mit einem <img>-Tag haben Sie mehr Kontrolle über das Laden eines Bilds, das für den Darstellungsbereich geeignet ist, und ermöglichen dem vorab ladenden Scanner, es zu erkennen.

Einfügen zu vieler Ressourcen

Dabei wird eine Ressource innerhalb des HTML-Codes platziert. Mithilfe der Base64-Codierung können Sie Stylesheets in <style>-Elementen, Skripts in <script>-Elementen und praktisch jeder anderen Ressource inline einfügen.

Das Inlinen von Ressourcen kann schneller sein als das Herunterladen, da keine separate Anfrage für die Ressource ausgegeben wird. Sie wird direkt im Dokument angezeigt und sofort geladen. Es gibt jedoch erhebliche Nachteile:

  • Wenn Sie Ihren HTML-Code nicht im Cache speichern und dies bei einer dynamischen HTML-Antwort einfach nicht möglich ist, werden die Inline-Ressourcen nie im Cache gespeichert. Dies wirkt sich auf die Leistung aus, da die Inline-Ressourcen nicht wiederverwendbar sind.
  • Selbst wenn Sie HTML im Cache speichern können, werden Inline-Ressourcen nicht zwischen Dokumenten gemeinsam genutzt. Dies reduziert die Caching-Effizienz im Vergleich zu externen Dateien, die im Cache gespeichert und im gesamten Ursprung wiederverwendet werden können.
  • Wenn Sie zu viele Inline-Inhalte inline einfügen, verzögert sich der Vorabladen des Scanners, sodass er später im Dokument keine weiteren Ressourcen findet, da das Herunterladen dieser zusätzlichen Inline-Inhalte länger dauert.

Nehmen wir diese Seite als Beispiel. Unter bestimmten Bedingungen ist der LCP-Kandidat das Bild oben auf der Seite und das CSS befindet sich in einer separaten Datei, die von einem <link>-Element geladen wird. Die Seite verwendet außerdem vier Webschriftarten, die als separate Dateien von der CSS-Ressource angefordert werden.

Ein WebPageTest-Netzwerk-Wasserfalldiagramm einer Seite mit einer externen CSS-Datei und vier Schriftarten, auf die verwiesen wird. Das Bild des LCP-Kandidaten wird zu gegebener Zeit vom Preload Scanner erkannt.
Abbildung 12: Ein WebPageTest-Netzwerk-Abfolgediagramm für eine Webseite, die in Chrome auf einem Mobilgerät über eine simulierte 3G-Verbindung ausgeführt wird. Der LCP-Kandidat der Seite ist ein Bild, das von einem <img>-Element geladen wird. Es wird jedoch vom Preload-Scanner erkannt, weil das CSS und die Schriftarten, die für den Seitenaufbau erforderlich sind, in separaten Ressourcen bereitgestellt werden, wodurch der Vorab-Scanner nicht verzögert wird.

Was passiert jetzt, wenn die CSS und alle Schriftarten als base64-Ressourcen inline eingefügt werden?

Ein WebPageTest-Netzwerk-Wasserfalldiagramm einer Seite mit einer externen CSS-Datei und vier Schriftarten, auf die verwiesen wird. Die Erkennung des LCP-Bilds durch den Preload-Scanner verzögert sich erheblich .
Abbildung 13: Ein WebPageTest-Netzwerk-Abfolgediagramm für eine Webseite, die in Chrome auf einem Mobilgerät über eine simulierte 3G-Verbindung ausgeführt wird. Der LCP-Kandidat der Seite ist ein Bild, das von einem <img>-Element geladen wird. Durch die Inline-Funktion des CSS-Codes und seine vier Schriftressourcen in "` wird das Bild erst dann vom Scanner für das Vorabladen erkannt, wenn diese Ressourcen vollständig heruntergeladen wurden.

Die Auswirkung einer Inline-Anzeige hat in diesem Beispiel negative Auswirkungen auf den LCP – und auf die Leistung im Allgemeinen. Die Version der Seite, die keine Inline-Elemente enthält, zeichnet das LCP-Bild nach etwa 3,5 Sekunden auf. Die Seite, auf der alles inline angezeigt wird, zeichnet das LCP-Bild erst etwas mehr als 7 Sekunden auf.

Hier steckt noch mehr als nur der Scanner zum Vorabladen. Das Inline-Format von Schriftarten ist keine gute Strategie, da base64 ein ineffizientes Format für binäre Ressourcen ist. Ein weiterer Faktor ist, dass externe Schriftartenressourcen nur dann heruntergeladen werden, wenn dies vom CSSOM als notwendig erachtet wird. Wenn diese Schriftarten als base64-Schriftarten gekennzeichnet sind, werden sie heruntergeladen, unabhängig davon, ob sie für die aktuelle Seite erforderlich sind oder nicht.

Könnte ein Vorabladen hier Verbesserungen bewirken? Sehr gern. Sie könnten das LCP-Bild vorab laden und die LCP-Zeit verkürzen. Das Aufblähen Ihres potenziell nicht im Cache ablegbaren HTML-Codes mit Inline-Ressourcen hat jedoch andere negative Auswirkungen auf die Leistung. Von diesem Muster ist auch First Contentful Paint (FCP) betroffen. In der Version der Seite, in der nichts eingefügt ist, beträgt FCP etwa 2,7 Sekunden. In der Version, in der alles inline ist, beträgt die FCP etwa 5,8 Sekunden.

Gehen Sie mit Inline-Elementen in HTML, insbesondere base64-codierten Ressourcen sorgsam vor. Im Allgemeinen wird dies abgesehen von sehr kleinen Ressourcen nicht empfohlen. So wenig wie möglich in die Halterung ein, denn zu viel Inline-Einbau spielt mit dem Feuer.

Markup mit clientseitigem JavaScript rendern

Zweifellos beeinflusst JavaScript die Seitengeschwindigkeit. Entwickler verlassen sich nicht nur auf Interaktivität, sondern auch, um Inhalte selbst bereitzustellen. Dies führt in gewisser Weise zu einer besseren Erfahrung für Entwickler: Vorteile für Entwickler bedeuten jedoch nicht immer auch Vorteile für die Nutzer.

Ein Muster, das den Preloader-Scanner austricksen kann, ist das Rendern von Markup mit clientseitigem JavaScript:

WebPageTest-Netzwerkwasserfall, der eine einfache Seite mit Bildern und Text zeigt, die vollständig im Client in JavaScript gerendert werden. Da die Auszeichnung in JavaScript enthalten ist, kann der Scanner zum Vorabladen keine der Ressourcen erkennen. Alle Ressourcen werden außerdem aufgrund des zusätzlichen Netzwerks und der zusätzlichen Verarbeitungszeit verzögert, die JavaScript-Frameworks benötigen.
Abbildung 14: Ein WebPageTest-Netzwerk-Abfolgediagramm für eine clientseitig gerenderte Webseite, die in Chrome auf einem Mobilgerät über eine simulierte 3G-Verbindung ausgeführt wird. Da sich die Inhalte in JavaScript befinden und zum Rendern ein Framework erforderlich ist, wird die Bildressource im clientseitig gerenderten Markup für den Preloader ausgeblendet. Die entsprechende, vom Server gerenderte Funktion ist in Abbildung 9.

Wenn Markup-Nutzlasten in JavaScript im Browser enthalten sind und vollständig von dort gerendert werden, sind alle Ressourcen in dieser Auszeichnung für den Preload-Scanner unsichtbar. Dadurch wird die Erkennung wichtiger Ressourcen verzögert, was sich auf die LCP auswirkt. In diesen Beispielen ist die Anfrage nach dem LCP-Bild im Vergleich zur entsprechenden Serverdarstellung, für die kein JavaScript erforderlich ist, erheblich verzögert.

Das weicht ein wenig vom Schwerpunkt dieses Artikels ab, aber die Auswirkungen des Markup-Renderings auf dem Client gehen weit über das Verhindern des Pre-Load-Scanners hinaus. Wenn Sie beispielsweise JavaScript einführen, um eine Erfahrung zu ermöglichen, die nicht erforderlich ist, führt dies zu unnötiger Verarbeitungszeit, die sich auf die Interaction to Next Paint (INP) auswirken kann. Das Rendern extrem großer Markups auf dem Client führt mit größerer Wahrscheinlichkeit zu langen Aufgaben als bei der gleichen Menge an Markup, die vom Server gesendet wird. Der Grund hierfür – abgesehen von der zusätzlichen Verarbeitung durch JavaScript – besteht darin, dass Browser Markups vom Server streamen und das Rendering so aufteilen, dass lange Aufgaben tendenziell eingeschränkt werden. Vom Client gerendertes Markup hingegen wird als eine einzelne, monolithische Aufgabe gehandhabt, die sich auf den INP einer Seite auswirken kann.

Die Abhilfe für dieses Szenario hängt von der Antwort auf diese Frage ab: Gibt es einen Grund, warum das Markup Ihrer Seite nicht vom Server bereitgestellt werden kann und nicht vom Client gerendert wird? Lautet die Antwort „nein“, sollte nach Möglichkeit serverseitiges Rendering (SSR) oder statisch generiertes Markup in Betracht gezogen werden, da der Scanner so wichtige Ressourcen vorab ermitteln und bei Bedarf abrufen kann.

Falls für Ihre Seite JavaScript erforderlich ist, um einige Teile Ihres Seiten-Markups mit Funktionen zu versehen, können Sie dies mit SSR auch mithilfe von einfachem JavaScript oder Hydration tun, um das Beste aus beiden Welten herauszuholen.

Der Preload-Scanner hilft Ihnen

Der Preload-Scanner ist eine äußerst effektive Browser-Optimierung, mit der Seiten beim Start schneller geladen werden. Wenn Sie Muster vermeiden, die es verhindern, wichtige Ressourcen im Voraus zu ermitteln, erleichtern Sie sich nicht nur die Entwicklung, sondern verbessern auch die Nutzererfahrung, die bei vielen Messwerten, einschließlich einiger Web Vitals, bessere Ergebnisse liefert.

Hier noch einmal die wichtigsten Punkte aus diesem Beitrag:

  • Der Browser-Preload-Scanner ist ein sekundärer HTML-Parser, der vor dem primären Parser sucht, wenn er blockiert wird, um opportunistisch Ressourcen zu finden, die er früher abrufen kann.
  • Ressourcen, die nicht in der vom Server bei der ersten Navigationsanfrage bereitgestellten Markup vorhanden sind, können vom Preload-Scanner nicht gefunden werden. Der Scanner zum Vorabladen kann unter anderem folgende Ursachen haben:
    • Einfügen von Ressourcen in das DOM mit JavaScript, z. B. Skripts, Bilder, Stylesheets oder andere Elemente, die in der anfänglichen Markup-Nutzlast vom Server besser geeignet wären.
    • Lazy Loading von „above the fold“-Bildern oder iFrames mithilfe einer JavaScript-Lösung
    • Markup wird auf dem Client gerendert und kann Verweise auf untergeordnete Dokumentressourcen mit JavaScript enthalten.
  • Der Scanner für Vorabladevorgänge scannt nur HTML. Es werden nicht die Inhalte anderer Ressourcen, insbesondere CSS, untersucht, die Verweise auf wichtige Assets enthalten können, einschließlich LCP-Kandidaten.

Wenn Sie aus irgendeinem Grund ein Muster nicht vermeiden können, das sich negativ auf die Geschwindigkeit des Vorabladenscanners auswirkt, sollten Sie den Ressourcenhinweis rel=preload berücksichtigen. Falls Sie rel=preload verwenden, testen Sie mit Lab-Tools, ob Sie den gewünschten Effekt erzielen. Schließlich sollten Sie nicht zu viele Ressourcen vorab laden, denn wenn Sie alles priorisieren, wird es nichts mehr geben.

Ressourcen

Hero-Image von Unsplash, von Mohammad Rahmani