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 nehmen bestimmte Optimierungen vor, um die Leistung auf eine Weise zu verbessern, die wir als Entwickler nicht können – aber nur, solange diese Optimierungen nicht unbeabsichtigt verhindert werden.

Eine der wichtigsten internen Browser-Optimierungen ist der Scanner zum Vorabladen des Browsers. 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.

<ph type="x-smartling-placeholder">
</ph> HTML-Parser-Diagramm. <ph type="x-smartling-placeholder">
</ph> 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 werden sowohl das Parsen als auch das Rendern blockiert, um ein Flash of Unstyled Content (FOUC) zu verhindern, bei dem eine Version einer Seite ohne Stil kurz zu sehen ist, bevor Stile darauf angewendet werden.

<ph type="x-smartling-placeholder">
</ph> Die web.dev-Startseite im unformatierten Zustand (links) und im Status mit benutzerdefiniertem Stil (rechts). <ph type="x-smartling-placeholder">
</ph> Abb. 2: Ein simuliertes Beispiel für FOUC. Links sehen Sie die Startseite von web.dev ohne Stile. Rechts sehen Sie dieselbe Seite mit angewendeten Stilen. 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.

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 die Browser, diese Probleme mithilfe eines sekundären HTML-Parsers, dem Preload Scanner, zu minimieren.

<ph type="x-smartling-placeholder">
</ph> Ein Diagramm des primären HTML-Parsers (links) und des Preload-Scanners (rechts), bei dem es sich um den sekundären HTML-Parser handelt. <ph type="x-smartling-placeholder">
</ph> 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.

So erkennen Sie, ob der Scanner zum Vorabladen 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 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 es in der Netzwerkabfolge einfacher zu erkennen, wo der Preload-Scanner arbeitet.

<ph type="x-smartling-placeholder">
</ph> Im WebPageTest-Netzwerk-Wasserfalldiagramm wird eine künstliche Verzögerung von 2 Sekunden für das Stylesheet dargestellt. <ph type="x-smartling-placeholder">
</ph> 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 Vermittlungsabfolge sehen können, erkennt der Scanner zum Vorabladen das <img>-Element, auch wenn das Rendering und das Parsen von Dokumenten 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 dieses Spielzeugbeispiel aus dem Weg geräumt haben, schauen wir uns einige reale Muster an, bei denen der Vorabladescanner besiegt werden kann – und was getan werden kann, um sie zu beheben.

async Script eingefügt

Angenommen, Ihre <head> enthält HTML-Code mit Inline-JavaScript wie diesem:

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

<ph type="x-smartling-placeholder">
</ph> Dieses WebPageTest-Diagramm zeigt den Vorabladescan, der beim Einschleusen eines Skripts abgebrochen wird. <ph type="x-smartling-placeholder">
</ph> 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 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 kommt das erste Byte der Navigationsanfrage an.
  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 Skripts so schnell wie möglich 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 ist das Ergebnis:

<ph type="x-smartling-placeholder">
</ph> 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. <ph type="x-smartling-placeholder">
</ph> 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.

Sie könnten vermuten, 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?

<ph type="x-smartling-placeholder">
</ph> 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. <ph type="x-smartling-placeholder">
</ph> 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, aber das async-Skript wird 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. Nehmen wir als Beispiel dieses Bild-Markup:

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

<ph type="x-smartling-placeholder">
</ph> 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. <ph type="x-smartling-placeholder">
</ph> 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, 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 Vorabladescanner die Bildressource nicht spekulativ vorab abrufen kann, möglicherweise während des Zeitpunkts, an dem das Rendering des Stylesheets blockiert wird, beeinträchtigt 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.

<ph type="x-smartling-placeholder">
</ph> 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. <ph type="x-smartling-placeholder">
</ph> Abb. 9: Ein WebPageTest-Netzwerk-Wasserfalldiagramm mit einer Webseite, das 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 bei einer langsamen Verbindung um 100 Millisekunden. 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 werden nicht gescannt, z. B. CSS. Das heißt, es werden keine Bilder abgerufen, auf die das Attribut background-image verweist.

Wie HTML verarbeiten Browser CSS in ein eigenes Objektmodell, 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 der CSS-Eigenschaft background-image. Wenn Ressourcen geladen werden, geschieht Folgendes:

<ph type="x-smartling-placeholder">
</ph> 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 Paint-Zeit des LCP-Kandidaten verzögert wird. <ph type="x-smartling-placeholder">
</ph> Abb. 10: 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). 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 sehr defekt, 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">

Dieser rel=preload-Hinweis ist klein, hilft dem Browser aber dabei, das Bild schneller zu finden als sonst:

<ph type="x-smartling-placeholder">
</ph> 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. <ph type="x-smartling-placeholder">
</ph> 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). Mithilfe des rel=preload-Hinweises 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.

Zu viele Ressourcen inline einbinden

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 Vorablade-Scanner, sodass er später im Dokument keine weiteren Ressourcen findet, da das Herunterladen dieser zusätzlichen Inline-Inhalte länger dauert.

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

<ph type="x-smartling-placeholder">
</ph> 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. <ph type="x-smartling-placeholder">
</ph> Abb. 12: 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 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?

<ph type="x-smartling-placeholder">
</ph> Ein WebPageTest-Netzwerk-Wasserfalldiagramm einer Seite mit einer externen CSS-Datei und vier Schriftarten, auf die verwiesen wird. Die Erkennung des LCP-Bildes durch den Preload-Scanner verzögert sich erheblich . <ph type="x-smartling-placeholder">
</ph> Abb. 13: 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 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 reduzieren. Wenn Ihr potenziell nicht im Cache speicherbarer HTML-Code jedoch mit Inline-Ressourcen überladen ist, hat dies 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 der FCP-Wert ungefähr 2,7 Sekunden. In der Version, in der alles inline ist, beträgt 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 bei der Bereitstellung von Inhalten selbst. Dies führt in gewisser Weise zu einer besseren Erfahrung für die Entwickler: Vorteile für Entwickler bedeuten jedoch nicht immer auch Vorteile für die Nutzer.

Ein Muster, das den Vorabladescanner verhindern kann, ist das Rendern des Markups mit clientseitigem JavaScript:

<ph type="x-smartling-placeholder">
</ph> 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. <ph type="x-smartling-placeholder">
</ph> Abb. 14: Ein WebPageTest-Netzwerk-Wasserfalldiagramm einer vom Client gerenderten Webseite, das 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, vom Server gerenderte Funktion ist in Abbildung 9.

Wenn Markup-Nutzlasten in JavaScript im Browser enthalten 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 sicherlich auf den 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.

Dies weicht ein wenig vom Schwerpunkt dieses Artikels ab, aber die Auswirkungen des Markup-Renderings auf den Client gehen weit über das Verhindern des Preload-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, die Sie aus diesem Beitrag mitnehmen sollten:

  • 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: <ph type="x-smartling-placeholder">
      </ph>
    • 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
    • Rendern von Markup auf dem Client, das Verweise auf Dokumentunterressourcen 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 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