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 nicht behindern.

Ein oft übersehener Aspekt der Optimierung der Seitengeschwindigkeit ist, dass man ein wenig über die internen Abläufe von Browsern wissen muss. Browser nehmen bestimmte Optimierungen vor, um die Leistung zu verbessern, was wir als Entwickler nicht können – aber nur, solange diese Optimierungen nicht unbeabsichtigt behindert werden.

Eine interne Browseroptimierung, die Sie kennen sollten, ist der Browser-Preload-Scanner. In diesem Beitrag erfahren Sie, wie der Preload-Scanner funktioniert und vor allem, wie Sie ihn nicht behindern.

Was ist ein Preload-Scanner?

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

Diagramm des HTML-Parsers.
Abbildung 1: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, wodurch der Browser daran gehindert wird, den Rest des Dokuments zu parsen oder auch nur einen Teil davon zu rendern, bis das CSS heruntergeladen und geparst wurde.

Bei CSS-Dateien wird das Rendern blockiert, um ein FOUC (Flash of Unstyled Content) zu verhindern. Das ist ein kurzzeitiges Aufblitzen einer ungestalteten Version einer Seite, bevor die Formatierungen angewendet werden.

Die web.dev-Startseite im nicht formatierten Zustand (links) und im formatierten Zustand (rechts).
Abbildung 2:Ein simuliertes Beispiel für FOUC. Links sehen Sie die Startseite von web.dev ohne Formatierungen. Rechts ist dieselbe Seite mit angewendeten Stilen zu sehen. Der nicht formatierte Zustand kann kurzzeitig 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 er auf <script>-Elemente ohne defer- oder async-Attribut stößt.

Der Grund dafür ist, dass der Browser nicht sicher sein kann, ob ein bestimmtes Skript das DOM ändert, während der primäre HTML-Parser noch seine Arbeit verrichtet. Aus diesem Grund ist es üblich, JavaScript am Ende des Dokuments zu laden, damit die Auswirkungen von blockiertem Parsen und Rendern minimal sind.

Das sind gute Gründe dafür, warum der Browser sowohl das Parsen als auch das Rendern blockieren sollte. Das Blockieren dieser wichtigen Schritte ist jedoch unerwünscht, da dadurch die Suche nach anderen wichtigen Ressourcen verzögert werden kann. Glücklicherweise versuchen Browser, diese Probleme mithilfe eines sekundären HTML-Parsers, dem sogenannten Vorablade-Scanner, zu beheben.

Ein Diagramm des primären HTML-Parsers (links) und des Preload-Scanners (rechts), der der sekundäre HTML-Parser ist.
Abbildung 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, da er CSS lädt und verarbeitet, bevor er mit der Verarbeitung des Bild-Markups im <body>-Element beginnen kann. Der Preload-Scanner kann jedoch im Raw-Markup nach dieser Bildressource suchen und mit dem Laden beginnen, bevor der primäre HTML-Parser entsperrt wird.

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

So erkennen Sie, wann der Preload-Scanner aktiv ist

Der Preload-Scanner ist aufgrund des blockierten Renderns und Parsens vorhanden. Wenn diese beiden Leistungsprobleme nie auftreten würden, wäre der Preload-Scanner nicht sehr nützlich. Ob eine Webseite vom Scanner zum Vorabladen 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 Preload-Scanner funktioniert.

Diese Seite mit einfachem Text und Bildern und einem Stylesheet ist ein gutes Beispiel. Da CSS-Dateien sowohl das Rendern als auch das Parsen blockieren, führen Sie über einen Proxydienst eine künstliche Verzögerung von zwei Sekunden für das Stylesheet ein. Durch diese Verzögerung lässt sich im Netzwerk-Wasserfall besser erkennen, wo der Preload-Scanner aktiv ist.

Das WebPageTest-Netzwerk-Wasserfalldiagramm veranschaulicht eine künstliche Verzögerung von 2 Sekunden, die auf das Stylesheet angewendet wird.
Abbildung 4:Ein WebPageTest-Netzwerk-Wasserfalldiagramm einer Webseite, die in Chrome auf einem Mobilgerät über eine simulierte 3G-Verbindung ausgeführt wird. Obwohl das Stylesheet durch einen Proxy künstlich um zwei Sekunden verzögert wird, bevor es geladen wird, wird das Bild, das sich später in der Markup-Payload befindet, vom Preload-Scanner erkannt.

Wie im Wasserfalldiagramm zu sehen ist, erkennt der Scanner zum Vorabladen das <img>-Element auch dann, wenn das Rendern und Parsen des Dokuments blockiert wird. Ohne diese Optimierung kann der Browser während des Blockierungszeitraums keine Elemente abrufen. Außerdem wären mehr Ressourcenanfragen aufeinanderfolgend statt gleichzeitig.

Nach diesem einfachen Beispiel sehen wir uns nun einige Muster aus der Praxis an, bei denen der Preload-Scanner umgangen werden kann, und was dagegen unternommen werden kann.

Eingefügte async-Skripts

Angenommen, Sie haben HTML in Ihrem <head>, das Inline-JavaScript wie dieses enthält:

<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 Skript also eingefügt wird, verhält es sich so, als ob das Attribut async darauf angewendet worden wäre. Das bedeutet, dass es so schnell wie möglich ausgeführt wird und das Rendern 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 ist zu sehen, dass der Preload-Scan umgangen wird, wenn ein Skript eingefügt wird.
Abbildung 5:WebPageTest-Netzwerk-Wasserfalldiagramm einer 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 Skript während der Phase zur Blockierung des Renderings nicht erkennen, da es auf dem Client eingefügt wird.

Sehen wir uns das genauer an:

  1. Bei 0 Sekunden wird das Hauptdokument angefordert.
  2. Nach 1, 4 Sekunden kommt das erste Byte der Navigationsanfrage an.
  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, mit dem das async-Script eingefügt wird, erst nach diesem Stylesheet nach 2,6 Sekunden erfolgt, ist die Funktionalität, die das Script bietet, nicht so schnell wie möglich verfügbar.

Das ist suboptimal, weil die Anfrage für das Skript erst erfolgt, nachdem das Stylesheet heruntergeladen wurde. Dadurch wird die Ausführung des Skripts verzögert. Da das <img>-Element im vom Server bereitgestellten Markup enthalten ist, wird es vom Preload-Scanner erkannt.

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

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

Das Ergebnis:

Ein WebPageTest-Netzwerk-Wasserfall, der zeigt, wie ein asynchrones Skript, das mit dem HTML-Skriptelement geladen wird, vom Browser-Scanner zum Vorabladen erkannt wird, obwohl der primäre HTML-Parser des Browsers während des Herunterladens und der Verarbeitung eines Stylesheets blockiert ist.
Abbildung 6:WebPageTest-Netzwerk-Wasserfalldiagramm einer 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 Skript während der Phase zur Blockierung des Renderings und lädt es gleichzeitig mit dem CSS.

Es liegt vielleicht nahe, vorzuschlagen, dass diese Probleme durch die Verwendung von rel=preload behoben werden könnten. Das würde sicherlich 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 einfügt?

Ein WebPageTest-Wasserfalldiagramm, das zeigt, wie der Ressourcenhinweis „rel=preload“ verwendet wird, um die Erkennung eines asynchron eingefügten Skripts zu fördern – allerdings auf eine Weise, die unbeabsichtigte Nebenwirkungen haben kann.
Abbildung 7:Ein WebPageTest-Netzwerk-Wasserfalldiagramm 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 behoben, es entsteht aber ein neues: Das async-Script in den ersten beiden Demos wird trotz des Ladens im <head> mit der Priorität „Niedrig“ geladen, während das Stylesheet mit der Priorität „Höchst“ geladen wird. In der letzten Demo, in der das async-Script vorab geladen wird, wird das Stylesheet weiterhin mit der Priorität „Highest“ geladen, die Priorität des Scripts wurde jedoch auf „High“ heraufgestuft.

Wenn die Priorität einer Ressource erhöht wird, weist der Browser ihr mehr Bandbreite zu. Das bedeutet, dass es trotz der höchsten Priorität des Stylesheets zu Bandbreitenkonflikten kommen kann, weil die Priorität des Skripts erhöht wurde. Das kann bei langsamen Verbindungen oder bei sehr großen Ressourcen ein Faktor sein.

Die Antwort ist ganz einfach: Wenn ein Skript beim Start benötigt wird, sollte es nicht in das DOM eingefügt werden, da dies den Preload-Scanner beeinträchtigt. Experimentieren Sie nach Bedarf mit der Platzierung des <script>-Elements sowie mit Attributen wie defer und async.

Lazy Loading mit JavaScript

Lazy Loading ist eine gute Methode, um Daten zu sparen. Sie 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 Problemen mit der Auffindbarkeit von Ressourcen führen, wenn der Preload-Scanner verwendet wird. Außerdem kann es unnötig lange dauern, bis ein Verweis auf ein Bild gefunden, heruntergeladen, decodiert und präsentiert wird. Sehen wir uns dieses Beispiel für die Bildkennzeichnung 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-basierten Lazy Loadern. Wenn das Bild in den Darstellungsbereich gescrollt wird, entfernt der Lazy Loader das Präfix data-. Im vorherigen Beispiel wird also aus data-src src. Durch dieses Update wird der Browser aufgefordert, die Ressource abzurufen.

Dieses Muster ist erst dann problematisch, wenn es auf Bilder angewendet wird, die beim Start im Viewport sind. Da der Preload-Scanner das Attribut data-src nicht auf dieselbe Weise liest wie ein Attribut src (oder srcset), wird der Bildverweis nicht früher erkannt. Schlimmer noch: Das Bild wird erst geladen, nachdem das JavaScript für das Lazy Loading heruntergeladen, kompiliert und ausgeführt wurde.

Ein WebPageTest-Netzwerk-Wasserfalldiagramm, das zeigt, wie ein verzögert geladenes Bild, das sich beim Start im sichtbaren Bereich befindet, zwangsläufig verzögert wird, weil der Browser-Preload-Scanner die Bildressource nicht finden kann und das Bild erst geladen wird, wenn das für das verzögerte Laden erforderliche JavaScript geladen wird. Das Bild wird viel später als erwartet gefunden.
Abbildung 8:WebPageTest-Netzwerk-Wasserfalldiagramm für eine Webseite, die in Chrome auf einem Mobilgerät über eine simulierte 3G-Verbindung ausgeführt wird. Die Bildressource wird unnötigerweise verzögert geladen, obwohl sie beim Start im Darstellungsbereich sichtbar ist. Dadurch wird der Preload-Scanner umgangen und es kommt zu einer unnötigen Verzögerung.

Je nach Größe des Bildes, die vom Darstellungsbereich abhängen kann, ist es möglicherweise ein Kandidatenelement für Largest Contentful Paint (LCP). Wenn der Preload-Scanner die Bildressource nicht vorab abrufen kann, z. B. während das Rendern durch die Stylesheets der Seite blockiert wird, leidet der LCP.

Die Lösung besteht darin, die 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 beim Start im Darstellungsbereich sind, da der Preload-Scanner die Bildressource schneller erkennt und abruft.

Ein WebPageTest-Wasserfalldiagramm für das Netzwerk, das ein Ladeszenario für ein Bild im sichtbaren Bereich während des Starts darstellt. Das Bild wird nicht verzögert geladen. Das bedeutet, dass es nicht vom Laden des Skripts abhängt und der Preload-Scanner es früher erkennen kann.
Abbildung 9:WebPageTest-Netzwerk-Wasserfalldiagramm einer Webseite, die in Chrome auf einem Mobilgerät über eine simulierte 3G-Verbindung ausgeführt wird. Der Scanner zum Vorabladen erkennt die Bildressource, bevor CSS und JavaScript geladen werden. So kann der Browser die Ressource schneller laden.

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

CSS-Hintergrundbilder

Der Scanner zum Vorabladen im Browser scannt Markup. Andere Ressourcentypen wie CSS, die möglicherweise Abrufe für Bilder umfassen, auf die mit der background-image-Eigenschaft verwiesen wird, werden nicht gescannt.

Wie bei HTML verarbeiten Browser CSS in ein eigenes Objektmodell, das als CSSOM bezeichnet wird. Wenn externe Ressourcen beim Erstellen des CSSOM erkannt werden, werden sie zum Zeitpunkt der Erkennung angefordert und nicht vom Preload-Scanner.

Angenommen, das LCP-Kandidatenelement Ihrer Seite hat die CSS-Eigenschaft background-image. So werden Ressourcen geladen:

Ein WebPageTest-Netzwerk-Wasserfalldiagramm, das eine Seite mit einem LCP-Kandidaten zeigt, der über die CSS-Eigenschaft „background-image“ geladen wird. Da sich das LCP-Kandidatenbild in einem Ressourcentyp befindet, den der Preload-Scanner des Browsers nicht untersuchen kann, wird das Laden der Ressource verzögert, bis das CSS heruntergeladen und verarbeitet wurde. Dadurch wird die Renderingzeit des LCP-Kandidaten verzögert.
Abbildung 10:Ein WebPageTest-Netzwerk-Wasserfalldiagramm einer 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 wird erst abgerufen, wenn der CSS-Parser es findet.

In diesem Fall wird der Preload-Scanner nicht so sehr umgangen, sondern ist einfach nicht beteiligt. Wenn ein LCP-Kandidat auf der Seite jedoch aus einer background-image-CSS-Eigenschaft 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">

Dieser rel=preload-Hinweis ist klein, hilft dem Browser aber, das Bild früher zu erkennen:

Ein WebPageTest-Netzwerk-Wasserfalldiagramm, das zeigt, dass ein CSS-Hintergrundbild (der LCP-Kandidat) aufgrund der Verwendung eines rel=preload-Hinweises viel früher geladen wird. Die LCP-Zeit wird um etwa 250 Millisekunden verbessert.
Abbildung 11:WebPageTest-Netzwerk-Wasserfalldiagramm einer 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). Mit dem Hinweis rel=preload 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 erkannt, was die LCP-Zeit verkürzt. Dieser Hinweis kann zwar helfen, das Problem zu beheben, aber es ist möglicherweise besser, zu prüfen, ob der LCP-Kandidat für das Bild aus CSS geladen werden muss. Mit einem <img>-Tag haben Sie mehr Kontrolle über das Laden eines Bildes, das für den Viewport geeignet ist, und können gleichzeitig dafür sorgen, dass es vom Preload-Scanner erkannt wird.

Zu viele Ressourcen inline einfügen

Beim Inlining wird eine Ressource in den HTML-Code eingefügt. Sie können Stylesheets in <style>-Elementen, Skripts in <script>-Elementen und praktisch jede andere Ressource mit Base64-Codierung inline einfügen.

Das Inline-Einbinden von Ressourcen kann schneller sein als das Herunterladen, da keine separate Anfrage für die Ressource gesendet wird. Sie ist direkt im Dokument enthalten 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 eingefügten Ressourcen nie im Cache gespeichert. Das wirkt sich auf die Leistung aus, da die inline eingefügten Ressourcen nicht wiederverwendet werden können.
  • Auch wenn Sie HTML im Cache speichern können, werden Inline-Ressourcen nicht zwischen Dokumenten geteilt. Dadurch wird die Caching-Effizienz im Vergleich zu externen Dateien verringert, die über einen gesamten Ursprung hinweg gecacht und wiederverwendet werden können.
  • Wenn Sie zu viel inline einfügen, verzögert sich die Erkennung von Ressourcen weiter unten im Dokument durch den Preload-Scanner, da das Herunterladen der zusätzlichen Inline-Inhalte länger dauert.

Diese Seite ist ein Beispiel. Unter bestimmten Umständen ist das LCP-Kandidatenelement das Bild oben auf der Seite und das CSS befindet sich in einer separaten Datei, die über ein <link>-Element geladen wird. Auf der Seite werden außerdem vier Webfonts verwendet, die als separate Dateien aus der CSS-Ressource angefordert werden.

Ein WebPageTest-Netzwerk-Wasserfalldiagramm einer Seite mit einer externen CSS-Datei, in der auf vier Schriftarten verwiesen wird. Das LCP-Kandidatenbild wird vom Preload-Scanner rechtzeitig erkannt.
Abbildung 12:WebPageTest-Netzwerk-Wasserfalldiagramm einer 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. Es wird jedoch vom Preload-Scanner erkannt, da das CSS und die Schriftarten, die für den Seitenaufbau erforderlich sind, in separaten Ressourcen geladen werden. Dadurch wird der Preload-Scanner nicht verzögert.

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

Ein WebPageTest-Netzwerk-Wasserfalldiagramm einer Seite mit einer externen CSS-Datei, in der auf vier Schriftarten verwiesen wird. Der Preload-Scanner erkennt das LCP-Bild erst mit erheblicher Verzögerung .
Abbildung 13:Ein WebPageTest-Netzwerk-Wasserfalldiagramm einer 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 Inline-Einbinden des CSS und der vier Schriftartenressourcen im ``-Element kann der Preload-Scanner das Bild erst erkennen, wenn diese Ressourcen vollständig heruntergeladen wurden.

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

Hier spielt mehr als nur der Preload-Scanner eine Rolle. 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 Schriftartressourcen nur heruntergeladen werden, wenn sie vom CSSOM als notwendig erachtet werden. Wenn diese Schriftarten als Base64-Code eingefügt werden, werden sie heruntergeladen, unabhängig davon, ob sie für die aktuelle Seite benötigt werden oder nicht.

Könnte ein Preload hier Abhilfe schaffen? Klar. Sie könnten das LCP-Bild vorab laden und die LCP-Zeit verkürzen. Wenn Sie jedoch Ihr möglicherweise nicht im Cache speicherbares HTML mit Inline-Ressourcen aufblähen, hat das 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 eingefügt wird, beträgt der FCP etwa 2,7 Sekunden. In der Version, in der alles inline ist, beträgt der FCP etwa 5,8 Sekunden.

Seien Sie sehr vorsichtig, wenn Sie Elemente in HTML einfügen, insbesondere Base64-codierte Ressourcen. Im Allgemeinen wird dies nicht empfohlen, außer bei sehr kleinen Ressourcen. Inline-Formatierung sollte so wenig wie möglich verwendet werden, da sie riskant ist.

Markup mit clientseitigem JavaScript rendern

Es besteht kein Zweifel: JavaScript wirkt sich auf die Seitengeschwindigkeit aus. Entwickler sind nicht nur darauf angewiesen, um Interaktivität zu ermöglichen, sondern es gab auch eine Tendenz, sich darauf zu verlassen, dass Inhalte selbst bereitgestellt werden. Dies führt in mancher Hinsicht zu einer besseren Entwicklerumgebung, aber Vorteile für Entwickler bedeuten nicht immer Vorteile für Nutzer.

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

Ein WebPageTest-Netzwerk-Wasserfall für eine einfache Seite mit Bildern und Text, die vollständig auf dem Client in JavaScript gerendert wird. Da sich das Markup in JavaScript befindet, kann der Preload-Scanner keine der Ressourcen erkennen. Alle Ressourcen werden zusätzlich verzögert, da JavaScript-Frameworks zusätzliche Netzwerk- und Verarbeitungszeit benötigen.
Abbildung 14:Ein WebPageTest-Netzwerk-Wasserfalldiagramm einer clientseitig gerenderten 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 auf ein Framework angewiesen sind, ist die Bildressource im clientseitig gerenderten Markup für den Preload-Scanner verborgen. Die entsprechende serverseitig gerenderte Version ist in Abbildung 9 dargestellt.

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

Das geht zwar etwas über den Fokus dieses Artikels hinaus, aber die Auswirkungen des Renderns von Markup auf dem Client gehen weit über das Umgehen des Preload-Scanners hinaus. Wenn Sie JavaScript für eine Funktion einführen, für die es nicht erforderlich ist, wird unnötige Verarbeitungszeit benötigt, die sich auf Interaction to Next Paint (INP) auswirken kann. Wenn auf dem Client eine sehr große Menge an Markup gerendert wird, sind lange Aufgaben wahrscheinlicher als wenn dieselbe Menge an Markup vom Server gesendet wird. Der Grund dafür ist neben der zusätzlichen Verarbeitung, die JavaScript erfordert, dass Browser Markup vom Server streamen und das Rendern so aufteilen, dass lange Aufgaben tendenziell 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, sondern auf dem Client gerendert werden kann? Wenn die Antwort auf diese Frage „Nein“ lautet, sollten Sie nach Möglichkeit serverseitiges Rendering (SSR) oder statisch generiertes Markup in Betracht ziehen. So kann der Preload-Scanner wichtige Ressourcen vorab erkennen und opportunistisch abrufen.

Wenn auf Ihrer Seite JavaScript erforderlich ist, um einigen Teilen des Seiten-Markups Funktionen zuzuweisen, können Sie dies weiterhin mit SSR tun, entweder mit Vanilla JavaScript oder mit Hydration, um das Beste aus beiden Welten zu erhalten.

Dem Preload-Scanner helfen, Ihnen zu helfen

Der Preload-Scanner ist eine sehr effektive Browseroptimierung, mit der Seiten beim Start schneller geladen werden. Wenn Sie Muster vermeiden, die die Fähigkeit des Browsers beeinträchtigen, wichtige Ressourcen im Voraus zu erkennen, vereinfachen Sie nicht nur die Entwicklung, sondern schaffen auch eine bessere Nutzerfreundlichkeit, die sich in vielen Messwerten, einschließlich einiger Web Vitals, niederschlägt.

Hier noch einmal die wichtigsten Punkte aus diesem Beitrag:

  • Der Browser-Scanner zum Vorabladen ist ein sekundärer HTML-Parser, der vor dem primären Parser scannt, wenn dieser blockiert ist, um opportunistisch Ressourcen zu erkennen, die er früher abrufen kann.
  • Ressourcen, die nicht im Markup enthalten sind, das vom Server bei der ersten Navigationsanfrage bereitgestellt wird, können vom Preload-Scanner nicht erkannt werden. Der Preload-Scanner kann unter anderem auf folgende Weise umgangen werden:
    • Ressourcen mit JavaScript in das DOM einfügen, z. B. Skripts, Bilder oder Stylesheets. Diese sollten besser in der ursprünglichen Markup-Nutzlast vom Server enthalten sein.
    • Lazy Loading von Bildern oder iFrames, die sich über dem Falz befinden, mit einer JavaScript-Lösung.
    • Markup auf dem Client rendern, das mit JavaScript Verweise auf Dokumentunterressourcen enthalten kann.
  • Der Scanner zum Vorabladen scannt nur HTML. Es werden nicht die Inhalte anderer Ressourcen untersucht, insbesondere CSS, die möglicherweise Verweise auf wichtige Assets enthalten, einschließlich LCP-Kandidaten.

Wenn Sie aus irgendeinem Grund kein Muster vermeiden können, das die Fähigkeit des Preload-Scanners, die Ladegeschwindigkeit zu erhöhen, negativ beeinflusst, sollten Sie den Ressourcenhinweis rel=preload in Betracht ziehen. Wenn Sie rel=preload verwenden, testen Sie es mit Lab-Tools, um sicherzustellen, dass es den gewünschten Effekt erzielt. Laden Sie schließlich nicht zu viele Ressourcen vor, da sonst nichts priorisiert wird.

Ressourcen

Hero-Image von Unsplash, von Mohammad Rahmani .