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 oft übersehener Aspekt bei der Optimierung der Seitengeschwindigkeit 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 web.dev-Startseite im unformatierten Zustand (links) und mit einem 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 der JavaScript-Code häufig am Ende des Dokuments geladen, damit die Auswirkungen eines blockierten Parsens und Renderns geringfügig werden.

Dies sind gute Gründe dafür, dass der Browser sowohl das Parsen als auch das Rendern blockieren sollte. Dennoch ist es nicht wünschenswert, einen dieser wichtigen Schritte zu blockieren, da sie die Show aufhalten können, indem sie die Erkennung anderer wichtiger Ressourcen verzögern. 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.
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 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.

So erkennen Sie, ob der Scanner zum Vorabladen 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.

Nehmen wir als Beispiel diese Seite mit einfachem Text und Bildern mit einem Stylesheet. Da CSS-Dateien sowohl das Rendering 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 in der Netzwerkabfolge leichter zu 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 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 Bedarf abrufen und mehr Ressourcenanfragen wären aufeinanderfolgende anstatt gleichzeitig.

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 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 suboptimales Ergebnis:

In diesem WebPageTest-Diagramm wird gezeigt, dass der Vorab-Scan durch das Einschleusen eines Scripts verhindert 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-Skript. Der Scanner für das Vorabladen kann das Script während der Phase der Blockierung des Renderings nicht erkennen, da es auf dem Client eingefügt 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,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:

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 vermieden werden kann, 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 anzuzeigen, 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 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-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.
Abb. 8:Ein WebPageTest-Netzwerk-Wasserfalldiagramm mit einer Webseite, das in Chrome auf einem Mobilgerät über eine simulierte 3G-Verbindung ausgeführt wird. Für die Bildressource wird unnötigerweise Lazy Loading verwendet, obwohl sie beim Start im Darstellungsbereich sichtbar ist. Dadurch wird der Vorabladescanner deaktiviert und eine unnötige Verzögerung verursacht.

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 Darstellungsbereich während des Starts zeigt Das Bild wird nicht verzögert geladen. Es ist also nicht vom Skript zum Laden 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 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 Browser-Preload-Scanner 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 externe Ressourcen beim Erstellen des CSSOM erkannt werden, werden diese Ressourcen zum Zeitpunkt der Erkennung und nicht vom Preload-Scanner angefordert.

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 beginnt erst mit dem Abruf des Bildes, wenn es vom CSS-Parser gefunden wurde.

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 verkürzt sich um etwa 250 Millisekunden.
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 dem Preloader-Scanner, es zu finden.

Einfügen zu vieler Ressourcen

Dabei wird eine Ressource innerhalb des HTML-Codes platziert. 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 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. 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, da das Herunterladen dieser zusätzlichen Inline-Inhalte länger dauert.

Sehen Sie sich diese Seite als Beispiel an. 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 dargestellt.

Hier steckt noch mehr als nur der Scanner zum Vorabladen. 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-Schriftarten gekennzeichnet sind, werden sie heruntergeladen, unabhängig davon, ob sie für die aktuelle Seite erforderlich sind oder nicht.

Könnte ein Vorabladen die Situation verbessern? Sehr gern. Sie könnten das LCP-Bild vorab laden und die LCP-Zeit reduzieren. Wenn Ihr potenziell nicht im Cache speicherbarer HTML-Code jedoch mit Inline-Ressourcen überladen ist, hat dies 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 eingebettet 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 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. 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 Vorabladescanner verhindern kann, ist das Rendern des Markups mit clientseitigem JavaScript:

WebPageTest-Netzwerkwasserfall, der eine einfache Seite mit Bildern und Text zeigt, die vollständig im Client in JavaScript gerendert werden. 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 der Inhalt in JavaScript enthalten ist und zum Rendern ein Framework benötigt, wird die Bildressource in der vom Client gerenderten Auszeichnung vor dem Preload-Scanner verborgen. 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 nach dem LCP-Bild im Vergleich zur entsprechenden vom Server gerenderten Darstellung, 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 Preloading-Scanners hinaus. Zum einen führt die Einführung von JavaScript für eine Funktion, für die es nicht erforderlich ist, zu unnötigen Verarbeitungszeiten, die sich auf die Interaktion bis zur nächsten Darstellung (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 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. 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. So kann der Preloader wichtige Ressourcen im Voraus finden und bei Bedarf abrufen.

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 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 und erzielen bessere Ergebnisse bei vielen Messwerten, 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
    • Rendern von Markup auf dem Client, das Verweise auf Dokument-Unterressourcen mithilfe von JavaScript enthalten kann.
  • 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 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, wird nichts priorisiert.

Ressourcen

Hero-Image von Unsplash, von Mohammad Rahmani