Drittanbieter-JavaScript optimieren

Drittanbieter-Scripts beeinträchtigen die Leistung. Daher ist es wichtig, sie regelmäßig zu prüfen und effiziente Lademethoden zu verwenden. In diesem Codelab erfahren Sie, wie Sie das Laden von Drittanbieterressourcen optimieren. Dabei werden die folgenden Techniken behandelt:

  • Laden von Scripts verschieben

  • Nicht kritische Ressourcen per Lazy Loading laden

  • Vorabverbindung zu erforderlichen Quellen herstellen

Die enthaltene Beispiel-App enthält eine einfache Webseite mit drei Funktionen von Drittanbietern:

  • Ein eingebettetes Video

  • Eine Datenvisualisierungsbibliothek zum Rendern eines Liniendiagramms

  • Ein Widget zum Teilen in sozialen Medien

Screenshot der Seite mit hervorgehobenen Drittanbieterressourcen
Drittanbieterressourcen in der Beispiel-App

Sie beginnen damit, die Leistung der App zu messen, und wenden dann die einzelnen Techniken an, um verschiedene Aspekte der App-Leistung zu verbessern.

Leistung messen

Öffnen Sie zuerst die Beispiel-App im Vollbildmodus:

  1. Klicke auf Remix zum Bearbeiten, um das Projekt bearbeitbar zu machen.
  2. Wenn Sie sich eine Vorschau der Website ansehen möchten, drücken Sie App ansehen und dann Vollbild Vollbild.

Führen Sie eine Lighthouse-Leistungsprüfung auf der Seite durch, um die Ausgangsleistung zu ermitteln:

  1. Drücken Sie „Strg + Umschalttaste + J“ (oder „Befehlstaste + Option + J“ auf einem Mac), um die Entwicklertools zu öffnen.
  2. Klicken Sie auf den Tab Lighthouse.
  3. Klicken Sie auf Mobil.
  4. Klicken Sie das Kästchen Leistung an. Sie können die restlichen Kästchen im Bereich „Audits“ deaktivieren.
  5. Klicken Sie auf Simuliertes schnelles 3G, 4-fache CPU-Verlangsamung.
  6. Klicken Sie das Kästchen Speicherplatz freigeben an.
  7. Klicken Sie auf Analysen ausführen.

Wenn Sie eine Analyse auf Ihrem Computer ausführen, können die genauen Ergebnisse variieren. Sie sollten jedoch feststellen, dass die First Contentful Paint (FCP)-Zeit ziemlich hoch ist und dass Lighthouse zwei Möglichkeiten zur Untersuchung vorschlägt: Renderblockierende Ressourcen entfernen und Vorabverbindung zu erforderlichen Ursprüngen herstellen. Auch wenn alle Messwerte grün sind, können Optimierungen zu Verbesserungen führen.

Screenshot der Lighthouse-Prüfung mit einem 2,4-sekündigen FCP und zwei Möglichkeiten: Ressourcen entfernen, die das Rendering blockieren, und Vorverbindung zu erforderlichen Ursprüngen herstellen

JavaScript von Drittanbietern verzögern

Bei der Prüfung Eliminieren Sie Ressourcen, die das Rendering blockieren, haben Sie festgestellt, dass Sie Zeit sparen können, indem Sie ein Script von d3js.org verschieben:

Screenshot der Prüfung „Ressourcen entfernen, die das Rendering blockieren“ mit dem hervorgehobenen Script „d3.v3.min.js“

D3.js ist eine JavaScript-Bibliothek zum Erstellen von Datenvisualisierungen. In der Datei script.js der Beispielanwendung werden D3-Dienstprogrammfunktionen verwendet, um das SVG-Liniendiagramm zu erstellen und der Seite anzuhängen. Die Reihenfolge der Vorgänge ist hier wichtig: script.js muss ausgeführt werden, nachdem das Dokument geparst und die D3-Bibliothek geladen wurde. Deshalb wird es direkt vor dem schließenden </body>-Tag in index.html eingefügt.

Das D3-Script ist jedoch in der <head> der Seite enthalten, was das Parsen des restlichen Dokuments blockiert:

Screenshot von index.html mit markiertem Script-Tag im Head

Mit zwei magischen Attributen kann der Parser entsperrt werden, wenn sie dem Script-Tag hinzugefügt werden:

  • async sorgt dafür, dass Scripts im Hintergrund heruntergeladen und bei der ersten Gelegenheit nach dem Download ausgeführt werden.

  • Mit defer werden Scripts im Hintergrund heruntergeladen und nach Abschluss des Parsings ausgeführt.

Da dieses Diagramm für die gesamte Seite nicht wirklich wichtig ist und sich höchstwahrscheinlich unterhalb des sichtbaren Bereichs befindet, prüfen Sie mit defer, ob es nicht vom Parser blockiert wird.

Schritt 1: Script asynchron mit dem Attribut defer laden

Fügen Sie in Zeile 17 in index.html dem Element <script> das Attribut defer hinzu:

<script src="https://d3js.org/d3.v3.min.js" defer></script>

Schritt 2: Auf die richtige Reihenfolge der Vorgänge achten

Jetzt, da D3 ausgesetzt ist, wird script.js ausgeführt, bevor D3 bereit ist, was zu einem Fehler führt.

Scripts mit dem defer-Attribut werden in der Reihenfolge ausgeführt, in der sie angegeben wurden. Damit script.js erst ausgeführt wird, wenn D3 fertig ist, fügen Sie defer hinzu und verschieben Sie es in das <head> des Dokuments, direkt nach dem D3-Element <script>. Jetzt wird der Parser nicht mehr blockiert und der Download beginnt früher.

<script src="https://d3js.org/d3.v3.min.js" defer></script>
<script src="./script.js" defer></script>

Drittanbieterressourcen per Lazy Load laden

Alle Ressourcen, die „below the fold“ (mit Scrollen sichtbar) sind, eignen sich gut für Lazy Loading.

In der Beispiel-App ist ein YouTube-Video in einen iFrame eingebettet. So kannst du prüfen, wie viele Anfragen die Seite stellt und welche vom eingebetteten YouTube-Iframe stammen:

  1. Wenn Sie sich eine Vorschau der Website ansehen möchten, drücken Sie App ansehen und dann Vollbild Vollbild.
  2. Drücken Sie „Strg + Umschalttaste + J“ (oder „Befehlstaste + Option + J“ auf einem Mac), um die Entwicklertools zu öffnen.
  3. Klicken Sie auf den Tab Netzwerk.
  4. Klicken Sie das Kästchen Cache deaktivieren an.
  5. Wählen Sie im Drop-down-Menü Drosselung die Option Schnelles 3G aus.
  6. Lade die Seite neu.

Screenshot des DevTools-Netzwerkbereichs

Im Bereich Netzwerk sehen Sie, dass für die Seite insgesamt 28 Anfragen gesendet und fast 1 MB komprimierte Ressourcen übertragen wurden.

Die von YouTube iframe gesendeten Anfragen findest du in der Spalte Initiator anhand der Video-ID 6lfaiXM6waw. So gruppieren Sie alle Anfragen nach Domain:

  • Klicken Sie im Bereich Netzwerk mit der rechten Maustaste auf einen Spaltentitel.

  • Wählen Sie im Drop-down-Menü die Spalte Domains aus.

  • Wenn Sie die Anfragen nach Domain sortieren möchten, klicken Sie auf den Spaltentitel Domains.

Die neue Sortierung zeigt, dass es zusätzliche Anfragen an Google-Domains gibt. Insgesamt werden über den YouTube-iFrame 14 Anfragen für Skripts, Stylesheets, Bilder und Schriftarten gestellt. Aber es sei denn, die Nutzer scrollen tatsächlich nach unten, um das Video abzuspielen, sind all diese Assets nicht wirklich erforderlich.

Wenn Sie mit dem Lazy Loading für das Video warten, bis ein Nutzer nach unten zu diesem Bereich der Seite scrollt, verringern Sie die Anzahl der Anfragen, die von der Seite anfänglich gestellt werden. So werden die Daten der Nutzer gespeichert und das initiale Laden beschleunigt.

Eine Möglichkeit, Lazy Loading zu implementieren, ist die Verwendung des Intersection Observers, einer Browser-API, die benachrichtigt, wenn ein Element den Darstellungsbereich des Browsers betritt oder verlässt.

Schritt 1: Verhindern, dass das Video zuerst geladen wird

Für das Lazy Loading des Video-iFrames müssen Sie zuerst verhindern, dass er wie gewohnt geladen wird. Ersetze dazu das Attribut src durch das Attribut data-src, mit dem die Video-URL angegeben wird:

<iframe width="560" height="315" data-src="https://www.youtube.com/embed/lS9D6w1GzGY" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

data-src ist ein Datenattribut, mit dem Sie zusätzliche Informationen in Standard-HTML-Elementen speichern können. Datenattribute können beliebig benannt werden, solange sie mit „data-“ beginnen.

Ein Iframe ohne src wird einfach nicht geladen.

Schritt 2: Intersection Observer verwenden, um das Video per Lazy Loading zu laden

Damit das Video geladen wird, wenn ein Nutzer zu ihm scrollt, müssen Sie wissen, wann das passiert. Hier kommt die Intersection Observer API ins Spiel. Mit der Intersection Observer API können Sie eine Callback-Funktion registrieren, die ausgeführt wird, wenn ein zu verfolgendes Element den Darstellungsbereich betritt oder verlässt.

Erstellen Sie zuerst eine neue Datei und nennen Sie sie lazy-load.js:

  • Klicken Sie auf Neue Datei und geben Sie einen Namen ein.
  • Klicken Sie auf Diese Datei hinzufügen.

Fügen Sie das Script-Tag in den Kopf des Dokuments ein:

 <script src="/lazy-load.js" defer></script>

Erstellen Sie in lazy-load.js eine neue IntersectionObserver und übergeben Sie eine Callback-Funktion, die ausgeführt werden soll:

// create a new Intersection Observer
let observer = new IntersectionObserver(callback);

Geben Sie observer jetzt ein Zielelement an, das beobachtet werden soll (in diesem Fall der Video-Frame), indem Sie es als Argument in der observe-Methode übergeben:

// the element that you want to watch
const element = document.querySelector('iframe');

// register the element with the observe method
observer.observe(element);

callback erhält eine Liste von IntersectionObserverEntry-Objekten und das IntersectionObserver-Objekt selbst. Jeder Eintrag enthält ein target-Element und Eigenschaften, die unter anderem seine Abmessungen, seine Position und die Zeit beschreiben, zu der es in den Darstellungsbereich eingetreten ist. Eine der Eigenschaften von IntersectionObserverEntry ist isIntersecting – ein boolescher Wert, der gleich true ist, wenn das Element in den Darstellungsbereich gelangt.

In diesem Beispiel ist target die iframe. isIntersecting ist gleich true, wenn target den Darstellungsbereich betritt. Ersetzen Sie callback durch die folgende Funktion, um dies in Aktion zu sehen:

let observer = new IntersectionObserver(callback);
let observer = new IntersectionObserver(function(entries, observer) {
    entries.forEach(entry => {
      console.log(entry.target);
      console.log(entry.isIntersecting);
    });
  });
  1. Wenn Sie sich eine Vorschau der Website ansehen möchten, drücken Sie App ansehen und dann Vollbild Vollbild.
  2. Drücken Sie Strg + Umschalttaste + J (oder Befehlstaste + Optionstaste + J auf einem Mac), um die Entwicklertools zu öffnen.
  3. Klicken Sie auf den Tab Console.

Scrollen Sie nach oben und unten. Der Wert von isIntersecting sollte sich ändern und das Zielelement sollte in der Console protokolliert werden.

Soll das Video geladen werden, wenn der Nutzer zu seiner Position scrollt, verwenden Sie isIntersecting als Bedingung, um eine loadElement-Funktion auszuführen. Diese ruft den Wert aus dem data-src des iframe-Elements ab und legt ihn als src-Attribut des iframe-Elements fest. Dieser Vorgang löst das Laden des Videos aus. Rufe dann nach dem Laden des Videos die Methode unobserve auf dem observer auf, um die Wiedergabe des Zielelements zu beenden:

let observer = new IntersectionObserver(function (entries, observer) {
  entries.forEach(entry => {
    console.log(entry.target);
    console.log(entry.isIntersecting);
  });
});
    if (entry.isIntersecting) {
      // do this when the element enters the viewport
      loadElement(entry.target);
      // stop watching
      observer.unobserve(entry.target);
    }
  });
});

function loadElement(element) {
  const src = element.getAttribute('data-src');
  element.src = src;
}

Schritt 3: Leistung noch einmal bewerten

Wenn Sie sehen möchten, wie sich die Größe und Anzahl der Ressourcen geändert hat, öffnen Sie den Bereich Netzwerk in den Entwicklertools und aktualisieren Sie die Seite noch einmal. Im Bereich Netzwerk sehen Sie, dass für die Seite 14 Anfragen und nur 260 KB gesendet wurden. Das ist eine deutliche Verbesserung.

Scrollen Sie jetzt auf der Seite nach unten und achten Sie auf den Bereich Netzwerk. Wenn Sie das Video aufrufen, sollten Sie sehen, dass die Seite zusätzliche Anfragen auslöst.

Vorabverbindung zu erforderlichen Ursprüngen herstellen

Sie haben nicht kritisches JavaScript verschoben und die YouTube-Anfragen mit Lazy Loading geladen. Jetzt ist es an der Zeit, die verbleibenden Drittanbieterinhalte zu optimieren.

Wenn Sie einem Link das Attribut rel=preconnect hinzufügen, wird der Browser angewiesen, eine Verbindung zu einer Domain herzustellen, bevor die Anfrage für diese Ressource gesendet wird. Dieses Attribut eignet sich am besten für Ursprünge, die Ressourcen bereitstellen, die für die Seite erforderlich sind.

Die Lighthouse-Analyse, die Sie im ersten Schritt unter Vorabverbindung zu erforderlichen Ursprüngen herstellen ausgeführt haben, hat ergeben, dass Sie etwa 400 ms einsparen können, wenn Sie vorzeitige Verbindungen zu staticxx.facebook.com und youtube.com herstellen:

Vorabverbindung zu erforderlichen Quellen prüfen, wobei die Domain staticxx.facebook.com hervorgehoben ist.

Da das YouTube-Video jetzt mit Lazy Loading geladen wird, bleibt nur noch staticxx.facebook.com, die Quelle des Widgets zum Teilen in sozialen Medien. Um eine frühzeitige Verbindung zu dieser Domain herzustellen, fügen Sie einfach ein <link>-Tag zum <head> des Dokuments hinzu:

  <link rel="preconnect" href="https://staticxx.facebook.com">

Leistung neu bewerten

Hier sehen Sie den Status der Seite nach der Optimierung. Führen Sie die Schritte im Codelab im Abschnitt Leistung messen aus, um eine weitere Lighthouse-Analyse auszuführen.

Lighthouse-Analyse mit einem FCP von 1 Sekunde und einer Leistungsbewertung von 99