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. Folgende Techniken werden behandelt:

  • Laden von Scripts verzögern

  • Lazy Loading nicht kritischer Ressourcen

  • 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 + Optionstaste + J“ auf einem Mac), um die Entwicklertools zu öffnen.
  2. Klicken Sie auf den Tab Lighthouse.
  3. Klicken Sie auf Mobilgeräte.
  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 einer Lighthouse-Analyse mit einem FCP von 2,4 Sekunden und zwei Verbesserungsmöglichkeiten: Renderblockierende Ressourcen beseitigen und mit erforderlichen Ursprüngen vorverbinden.

JavaScript von Drittanbietern verzögern

Bei der Prüfung Ressourcen beseitigen, die das Rendering blockieren wurde 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

Da D3 jetzt verschoben wird, 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>

Lazy-Load-Drittanbieterressourcen

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 einem 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 + Optionstaste + 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 Scripts, 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 das Video erst dann per Lazy-Load laden, wenn ein Nutzer zu diesem Bereich der Seite scrollt, verringern Sie die Anzahl der Anfragen, die die Seite anfangs sendet. 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: Videoanfang verhindern

Wenn Sie den Video-Frame per Lazy Load laden möchten, müssen Sie zuerst verhindern, dass er auf die übliche Weise geladen wird. Ersetzen Sie dazu das Attribut src durch das Attribut data-src, um die Video-URL anzugeben:

<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 zum Lazy-Load des Videos verwenden

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 Element, das Sie erfassen möchten, den Viewport 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 ihr eine auszuführende Callback-Funktion:

// 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 Properties von IntersectionObserverEntry ist isIntersecting, ein boolescher Wert, der true entspricht, wenn sich das Element im Darstellungsbereich befindet.

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.

Wenn das Video geladen werden soll, wenn der Nutzer zu seiner Position scrollt, verwenden Sie isIntersecting als Bedingung, um eine loadElement-Funktion auszuführen, die den Wert aus dem data-src-Attribut des iframe-Elements abrufen und als src-Attribut des iframe-Elements festlegen. 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 verzögert geladen wird, bleibt nur 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 noch einmal 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