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 ihn aus dem Weg gehen können.

Ein Aspekt, der bei der Optimierung der Seitengeschwindigkeit oft übersehen wird, ist das Wissen über die internen Abläufe von Browsern. 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 ist der Browser-Preload-Scanner. In diesem Beitrag erfahren Sie, wie der Preloader funktioniert und vor allem, wie Sie ihn nicht behindern.

Was ist ein Preloader-Scanner?

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

HTML-Parser-Diagramm.
Abbildung 1:Ein Diagramm, das zeigt, wie der primäre HTML-Parser des Browsers blockiert werden kann. In diesem Fall stößt der Parser auf ein <link>-Element für eine externe CSS-Datei, was den Browser daran hindert, den Rest des Dokuments zu parsen oder überhaupt zu rendern, 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).
Abbildung 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. Der Zustand ohne Stil kann blitzschnell auftreten, wenn der Browser das Rendering nicht blockiert, während ein Stylesheet heruntergeladen und verarbeitet wird.

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

Der Grund dafür ist, dass der Browser nicht sicher weiß, ob ein bestimmtes Script das DOM ändert, während der primäre HTML-Parser noch seine Arbeit erledigt. Aus diesem Grund wird JavaScript häufig am Ende des Dokuments geladen, damit die Auswirkungen des blockierten Parsings und Renderings marginal 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 Browser, diese Probleme mithilfe eines sekundären HTML-Parsers namens Preloader zu minimieren.

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

Die Rolle eines Preloader-Scanners ist spekulativ. Das bedeutet, dass er das Roh-Markup untersucht, um Ressourcen zu finden, die opportunistisch abgerufen werden, bevor sie sonst vom primären HTML-Parser gefunden werden.

Prüfen, ob der Preloader funktioniert

Der Prefetch-Scanner wird aufgrund blockierter Rendering- und Parsevorgänge verwendet. Wenn diese beiden Leistungsprobleme nicht auftreten würden, wäre der Preloader nicht sehr nützlich. Ob eine Webseite vom Preloader profitiert, hängt von diesen Blockierungsphänomenen ab. Dazu können Sie eine künstliche Verzögerung für Anfragen einführen, um herauszufinden, wo der Preloader funktioniert.

Sehen wir uns als Beispiel diese Seite mit einfachem Text und Bildern mit einem Stylesheet an. Da CSS-Dateien sowohl das Rendering als auch das Parsen blockieren, wird durch einen Proxydienst eine künstliche Verzögerung von zwei Sekunden für das Stylesheet eingeführt. Durch diese Verzögerung lässt sich in der Netzwerkabfolge leichter erkennen, wo der Preloader-Scanner aktiv ist.

Das Netzwerk-Wasserfalldiagramm von WebPageTest zeigt eine künstliche Verzögerung von 2 Sekunden für das Stylesheet.
Abbildung 4: Ein Netzwerk-Abfolgediagramm von WebPageTest für eine Webseite, die in Chrome auf einem Mobilgerät über eine simulierte 3G-Verbindung ausgeführt wird. Auch wenn das Stylesheet durch einen Proxy um zwei Sekunden verzögert wird, bevor es geladen wird, wird das Bild, das sich später in der Markup-Nutzlast befindet, vom Pre-Load-Scanner erkannt.

Wie Sie in der Ablaufgrafik sehen, erkennt der Preloader das <img>-Element auch dann, wenn das Rendering und das Parsen des Dokuments blockiert sind. Ohne diese Optimierung kann der Browser während des Blockierungszeitraums nicht opportunistisch Daten abrufen. Außerdem werden mehr Ressourcenanfragen nacheinander statt gleichzeitig gesendet.

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.

Eingeschleuste async-Scripts

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>

Eingebettete Scripts haben standardmäßig den Wert async. Wenn dieses Script eingebettet wird, verhält es sich so, als wäre das Attribut async darauf angewendet worden. Das bedeutet, dass es 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 suboptimales Ergebnis:

In diesem WebPageTest-Diagramm wird gezeigt, dass der Vorab-Scan verhindert wird, wenn ein Script eingefügt wird.
Abbildung 5:Ein WebPageTest-Netzwerk-Abfolgediagramm für eine Webseite, die 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 zum Vorabladen kann das Script während der Phase der Blockierung des Renderings nicht erkennen, da es auf dem Client eingefügt wird.

Sehen wir uns an, was hier 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, 0 Sekunden werden das CSS und das Bild angefordert.
  4. Da der Parser das Laden des Stylesheets blockiert und das Inline-JavaScript, das das async-Script einschleust, nach diesem Stylesheet mit 2,6 Sekunden kommt, sind die Funktionen des Scripts nicht so schnell verfügbar, wie sie es sein könnten.

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

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

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

Das Ergebnis sieht so aus:

Eine WebPageTest-Netzwerkabfolge, die zeigt, wie ein asynchrones Script, das mit dem HTML-Script-Element geladen wird, vom Browser-Vorab-Lade-Scanner erkannt werden kann, auch wenn der primäre HTML-Parser des Browsers beim Herunterladen und Verarbeiten eines Stylesheets blockiert ist.
Abbildung 6: Ein WebPageTest-Netzwerk-Abfolgediagramm für eine Webseite, die 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 Script während der Phase der Blockierung des Renderings 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 zwar funktionieren, kann aber einige Nebenwirkungen haben. Warum sollte man rel=preload verwenden, um ein Problem zu beheben, das sich vermeiden lässt, indem man kein <script>-Element in das DOM einschleust?

Eine WebPageTest-Abfolge, die zeigt, wie der Ressourcenhinweis „rel=preload“ verwendet wird, um die Erkennung eines asynchron eingeschleusten Scripts zu fördern – allerdings auf eine Weise, die unbeabsichtigte Nebenwirkungen haben kann.
Abbildung 7:Ein WebPageTest-Netzwerk-Abfolgediagramm für eine Webseite, die 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. Das async-Script wird jedoch vorab geladen, damit es schneller erkannt wird.

Durch das Vorladen wird das Problem hier zwar behoben, aber es entsteht ein neues: Das async-Script in den ersten beiden Demos wird – obwohl es im <head> geladen wird – mit der Priorität „Niedrig“ geladen, während das Stylesheet mit der Priorität „Höchste“ geladen wird. In der letzten Demo, in der das async-Script vorab geladen wird, wird das Stylesheet weiterhin mit der Priorität „Höchste“ geladen, die Priorität des Scripts wurde jedoch auf „Hoch“ erhöht.

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

Die Antwort ist einfach: Wenn ein Script beim Starten benötigt wird, sollten Sie den Preloader nicht durch Einschleusen in das DOM austricksen. Experimentieren Sie nach Bedarf mit der Platzierung von <script>-Elementen sowie mit Attributen wie defer und async.

Lazy Loading mit JavaScript

Das Lazy-Loading ist eine gute Methode, um Daten zu sparen. Diese Methode wird häufig auf Bilder angewendet. Manchmal wird Lazy Loading jedoch fälschlicherweise auf Bilder angewendet, die sich sozusagen „above the fold“ befinden.

Dies kann zu potenziellen Problemen bei der Ressourcenerkennung durch den Preloader führen und die Zeit, die benötigt wird, um eine Referenz auf ein Bild zu finden, herunterzuladen, zu decodieren und zu präsentieren, unnötig verlängern. Sehen wir uns dieses Bild-Markup als Beispiel an:

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

Die Verwendung eines data--Präfixes ist ein gängiges Muster in JavaScript-basierten Lazy-Loadern. Wenn das Bild in den Viewport gescrollt wird, entfernt der Lazy-Loader das Präfix data-. Im vorherigen Beispiel wird also data-src zu src. 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 Viewport befinden. Da der Preloader das data-src-Attribut nicht auf dieselbe Weise liest wie ein src- (oder srcset-)Attribut, wird die Bildreferenz nicht früher erkannt. Schlimmer noch: Das Bild wird erst nach dem Herunterladen, Kompilieren und Ausführen des Lazy-Loader-JavaScripts geladen.

Ein WebPageTest-Netzwerk-Abfolgediagramm, das zeigt, wie ein verzögert geladenes Bild, das sich beim Starten im Viewport befindet, verzögert wird, weil der Browser-Preload-Scanner die Bildressource nicht finden kann. Es wird erst geladen, wenn das für das Lazy Loading erforderliche JavaScript geladen wird. Das Bild wird viel später als nötig erkannt.
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 unwirksam und führt zu einer unnötigen Verzögerung.

Je nach Größe des Bildes, was wiederum von der Größe des Darstellungsbereichs abhängen kann, kann es ein Element für 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">

Das ist das optimale Muster für Bilder, die sich beim Start im Viewport befinden, da der Preloader die Bildressource schneller erkennt und abruft.

Ein WebPageTest-Netzwerk-Wasserfalldiagramm, das ein Ladeszenario für ein Bild im Viewport während des Starts darstellt. Das Bild wird nicht verzögert geladen, d. h., es ist nicht vom Laden des Scripts abhängig. Daher kann es vom Preloader früher erkannt werden.
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 zum Vorabladen erkennt die Bildressource, bevor das Laden von CSS und JavaScript beginnt. Dadurch kann der Browser mit dem Laden beginnen, bevor die anderen Ressourcen geladen sind.

In diesem vereinfachten Beispiel führt dies zu einer Verbesserung des LCP um 100 Millisekunden bei einer langsamen Verbindung. Das mag nicht nach einer großen Verbesserung aussehen, aber das ist es, wenn man bedenkt, dass es sich um eine schnelle Korrektur des Markups handelt und dass die meisten Webseiten komplexer sind als diese Beispiele. Das bedeutet, dass sich LCP-Kandidaten möglicherweise mit vielen anderen Ressourcen um die Bandbreite streiten müssen. Daher werden Optimierungen wie diese immer wichtiger.

CSS-Hintergrundbilder

Der Scanner zum Vorabladen im Browser scannt Markup. Andere Ressourcentypen wie CSS werden nicht gescannt. Das kann Abrufe von Bildern erfordern, auf die über die background-image-Property verwiesen wird.

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.

Angenommen, der LCP-Kandidat Ihrer Seite ist ein Element mit einer CSS-background-image-Eigenschaft. Beim Laden von Ressourcen geschieht Folgendes:

Ein WebPageTest-Netzwerk-Wasserfalldiagramm mit einer Seite mit einem LCP-Kandidaten, der über die Hintergrundbild-Eigenschaft aus CSS geladen wird. Da sich das LCP-Kandidatenbild in einem Ressourcentyp befindet, den der Browser-Preload-Scanner nicht prüfen kann, wird das Laden der Ressource verzögert, bis das CSS heruntergeladen und verarbeitet wurde. Dadurch wird die Malzeit des LCP-Kandidaten verzögert.
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 einer CSS-background-image-Eigenschaft (Zeile 3). Das angeforderte Bild wird erst abgerufen, wenn der CSS-Parser es gefunden hat.

In diesem Fall wird der Preloader nicht so sehr umgangen, sondern spielt keine Rolle. Wenn ein LCP-Kandidat auf der Seite jedoch aus einer background-image-CSS-Property 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-Abfolgediagramm, das zeigt, dass ein CSS-Hintergrundbild (das LCP-Kandidat ist) aufgrund der Verwendung eines rel=preload-Hinweises viel früher geladen wird. Die LCP-Zeit wird um etwa 250 Millisekunden verbessert.
Abbildung 11: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 einer CSS-background-image-Eigenschaft (Zeile 3). Mit dem rel=preload-Hinweis kann der Browser das Bild etwa 250 Millisekunden früher erkennen als ohne den Hinweis.

Mit dem rel=preload-Hinweis wird der LCP-Kandidat früher gefunden, wodurch sich die LCP-Zeit verkürzt. Dieser Hinweis hilft zwar, dieses Problem zu beheben, aber es ist möglicherweise besser, zu prüfen, ob Ihr LCP-Kandidat für Bilder aus CSS geladen werden muss. Mit einem <img>-Tag haben Sie mehr Kontrolle über das Laden eines Bildes, das für den Darstellungsbereich geeignet ist, und ermöglichen gleichzeitig, dass es vom Preloader erkannt wird.

Einfügen zu vieler Ressourcen

Beim Inline-Verknüpfen wird eine Ressource in den HTML-Code eingefügt. Sie können Stylesheets in <style>-Elemente, Scripts in <script>-Elemente und praktisch jede andere Ressource mithilfe der Base64-Codierung inline einbinden.

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

  • Wenn Sie Ihr HTML nicht im Cache speichern – was bei dynamischen HTML-Antworten nicht möglich ist –, werden die Inline-Ressourcen nie im Cache gespeichert. Das wirkt sich auf die Leistung aus, da die eingefügten Ressourcen nicht wiederverwendet werden können.
  • Auch wenn Sie HTML im Cache speichern können, werden eingebettete Ressourcen nicht zwischen Dokumenten geteilt. Dies reduziert die Caching-Effizienz im Vergleich zu externen Dateien, die für einen gesamten Ursprung im Cache gespeichert und wiederverwendet werden können.
  • Wenn Sie zu viel Inline-Code verwenden, verzögert sich das Erkennen von Ressourcen später im Dokument durch den Preloader, da das Herunterladen dieser zusätzlichen Inline-Inhalte länger dauert.

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

Ein WebPageTest-Netzwerk-Abfolgediagramm einer Seite mit einer externen CSS-Datei, auf die vier Schriftarten verweisen. Das LCP-Kandidatenbild wird vom Preloader-Scanner rechtzeitig 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 über ein <img>-Element geladen wird. Er wird jedoch vom Preloader erkannt, da die für das Laden der Seite erforderlichen CSS-Dateien und Schriftarten in separaten Ressourcen gespeichert sind. Dadurch wird der Preloader nicht in seiner Arbeit behindert.

Was passiert, wenn das CSS und alle Schriftarten als Base64-Ressourcen eingefügt werden?

Ein WebPageTest-Netzwerk-Abfolgediagramm einer Seite mit einer externen CSS-Datei, auf die vier Schriftarten verweisen. Der Preloader benötigt deutlich mehr Zeit, um das LCP-Bild zu finden .
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 über ein <img>-Element geladen wird. Durch das Einfügen des CSS und der vier Schriftressourcen in den „“-Block wird der LCP-Scanner jedoch daran gehindert, das Bild zu erkennen, bis diese Ressourcen vollständig heruntergeladen wurden.

Die Auswirkungen des Inline-Einfügens haben in diesem Beispiel negative Folgen für die LCP und die Leistung im Allgemeinen. Auf der Version der Seite, auf der nichts inline ist, wird das LCP-Bild in etwa 3,5 Sekunden dargestellt. Auf der Seite, auf der alles inline ist, wird das LCP-Bild erst nach etwas mehr als 7 Sekunden gerendert.

Es geht hier nicht nur um den Preloader-Scanner. Das Einbetten von Schriftarten ist keine gute Strategie, da Base64 ein ineffizientes Format für binäre Ressourcen ist. Ein weiterer Faktor ist, dass externe Schriftressourcen nur heruntergeladen werden, wenn sie vom CSSOM als erforderlich eingestuft werden. Wenn diese Schriftarten als Base64-Inlining eingebunden sind, werden sie heruntergeladen, unabhängig davon, ob sie für die aktuelle Seite benötigt werden oder nicht.

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

Seien Sie vorsichtig, wenn Sie Inhalte in HTML einfügen, insbesondere Base64-codierte Ressourcen. Im Allgemeinen wird dies nicht empfohlen, es sei denn, es handelt sich um sehr kleine Ressourcen. Verwenden Sie Inline-Elemente so wenig wie möglich, da zu viele Inline-Elemente ein Sicherheitsrisiko darstellen.

Markup mit clientseitigem JavaScript rendern

Es besteht kein Zweifel: JavaScript wirkt sich definitiv auf die Seitenladezeit aus. Nicht nur Entwickler sind auf JavaScript angewiesen, um Interaktivität zu ermöglichen, sondern es gibt auch eine Tendenz, JavaScript für die Bereitstellung von Inhalten zu verwenden. Dies führt in gewisser Weise zu einer besseren Entwicklererfahrung. Vorteile für Entwickler bedeuten jedoch nicht immer Vorteile für Nutzer.

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

Eine WebPageTest-Netzwerkabfolge, die eine einfache Seite mit Bildern und Text zeigt, die vollständig auf dem Client in JavaScript gerendert wird. Da das Markup in JavaScript enthalten ist, kann der Preloader keine der Ressourcen erkennen. Alle Ressourcen werden zusätzlich verzögert, da JavaScript-Frameworks zusätzliche Netzwerk- und Verarbeitungszeit erfordern.
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 die Inhalte in JavaScript enthalten sind und zum Rendern ein Framework verwendet wird, ist die Bildressource im clientseitig gerenderten Markup für den Preloader-Scanner ausgeblendet. Die entsprechende servergerenderte Version ist in Abbildung 9 dargestellt.

Wenn Markup-Nutzlast in JavaScript im Browser enthalten und vollständig von JavaScript gerendert wird, sind alle Ressourcen in diesem Markup für den Preloader unsichtbar. Dadurch wird die Erkennung wichtiger Ressourcen verzögert, was sich auf die LCP auswirkt. In diesen Beispielen ist die Anfrage für das LCP-Bild erheblich verzögert, verglichen mit der entsprechenden servergerenderten Version, für die kein JavaScript erforderlich ist.

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. Zum einen führt die Verwendung von JavaScript für eine Funktion, die es nicht erfordert, zu unnötigen Verarbeitungszeiten, die sich auf die Interaktion bis zur nächsten Zeichnen-Aktion (Interaction to Next Paint, INP) auswirken können. Beim Rendern extrem großer Mengen an Markup auf dem Client ist die Wahrscheinlichkeit höher, dass lange Aufgaben generiert werden, als wenn dieselbe Menge an Markup vom Server gesendet wird. Der Grund dafür ist neben der zusätzlichen Verarbeitung durch JavaScript, dass Browser Markup vom Server streamen und das Rendering so in kleine Teile aufteilen, dass lange Aufgaben in der Regel begrenzt werden. Clientseitig gerendertes Markup wird dagegen als einzelne, monolithische Aufgabe behandelt, was sich auf den INP einer Seite auswirken kann.

Die Lösung 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, sondern auf dem Client gerendert werden muss? Wenn die Antwort „Nein“ lautet, sollten Sie nach Möglichkeit serverseitiges Rendering (SSR) oder statisch generiertes Markup in Betracht ziehen, da dies dem Preloader-Scanner hilft, wichtige Ressourcen im Voraus zu finden und zu erfassen.

Wenn für Ihre Seite JavaScript erforderlich ist, um einigen Teilen des Seiten-Markups Funktionen hinzuzufügen, können Sie dies auch mit SSR tun, entweder mit Vanilla-JavaScript oder mit Hydration, um das Beste aus beiden Welten zu nutzen.

Dem Preloader-Scanner helfen, Ihnen zu helfen

Der Preloader ist eine äußerst effektive Browseroptimierung, die das Laden von Seiten beim Starten beschleunigt. Wenn Sie Muster vermeiden, die die Fähigkeit von Lighthouse beeinträchtigen, wichtige Ressourcen im Voraus zu finden, vereinfachen Sie nicht nur die Entwicklung, sondern sorgen auch für eine bessere Nutzerfreundlichkeit, die zu besseren Ergebnissen bei vielen Messwerten führt, einschließlich einiger Web Vitals.

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 scannt, wenn dieser blockiert ist, um Ressourcen zu finden, die früher abgerufen werden können.
  • Ressourcen, die nicht im Markup vorhanden sind, das der Server bei der ersten Navigationsanfrage zur Verfügung stellt, können vom Pre-Load-Scanner nicht gefunden werden. Beispiele für Möglichkeiten, den Preloader-Scanner zu umgehen:
    • Ressourcen mit JavaScript in das DOM einschleusen, z. B. Scripts, Bilder, Stylesheets oder andere Elemente, die besser in der ursprünglichen Markup-Nutzlast vom Server enthalten wären.
    • Lazy Loading von Bildern oder iFrames im Above-the-Fold-Bereich mit einer JavaScript-Lösung
    • Markup wird auf dem Client gerendert und kann Verweise auf untergeordnete Dokumentressourcen mit JavaScript enthalten.
  • Der Scanner zum Vorabladen scannt nur HTML. Der Inhalt anderer Ressourcen, insbesondere CSS, wird nicht geprüft. Diese können Verweise auf wichtige Assets enthalten, einschließlich LCP-Kandidaten.

Wenn Sie aus irgendeinem Grund kein Muster vermeiden können, das die Fähigkeit des Preloader-Scanners, die Ladeleistung zu beschleunigen, negativ beeinträchtigt, sollten Sie den Ressourcenhinweis rel=preload berücksichtigen. Wenn Sie rel=preload verwenden, sollten Sie mithilfe von Lab-Tools prüfen, ob Sie den gewünschten Effekt erzielen. Laden Sie nicht zu viele Ressourcen vorab, denn wenn Sie alles priorisieren, ist nichts priorisiert.

Ressourcen

Hero-Image von Unsplash, von Mohammad Rahmani