JavaScript-Nutzlasten durch Codeaufteilung reduzieren

Die meisten Webseiten und Anwendungen bestehen aus vielen verschiedenen Teilen. Anstatt den gesamten JavaScript-Code der Anwendung direkt nach dem Laden der ersten Seite zu senden, wird die Seitenleistung verbessert, wenn der JavaScript-Code in mehrere Blöcke aufgeteilt wird.

In diesem Codelab wird gezeigt, wie Sie mithilfe der Codeaufteilung die Leistung einer einfachen Anwendung verbessern, in der drei Zahlen sortiert werden.

In einem Browserfenster wird eine Anwendung namens „Magischer Sortierung“ mit drei Feldern für die Eingabe von Zahlen und einer Schaltfläche zum Sortieren angezeigt.

Messen

Wie immer ist es wichtig, zuerst die Leistung einer Website zu messen, bevor Sie Optimierungen vornehmen.

  1. Um die Website als Vorschau anzusehen, wählen Sie App ansehen und dann Vollbild Vollbild aus.
  2. Drücken Sie Strg + Umschalttaste + J (oder Befehlstaste + Option + J auf dem Mac), um die Entwicklertools zu öffnen.
  3. Klicken Sie auf den Tab Netzwerk.
  4. Klicken Sie das Kästchen Cache deaktivieren an.
  5. Aktualisieren Sie die App.

Netzwerkbereich mit einem 71,2 KB großen JavaScript-Bundle.

71,2 KB JavaScript, um ein paar Zahlen in einer einfachen Anwendung zu sortieren. What gives?

Im Quellcode (src/index.js) wird die lodash-Bibliothek importiert und in dieser Anwendung verwendet. Lodash bietet viele nützliche Dienstfunktionen, aber hier wird nur eine Methode aus dem Paket verwendet. Ein häufiger Fehler besteht darin, ganze Abhängigkeiten von Drittanbietern zu installieren und zu importieren, von denen nur ein kleiner Teil genutzt wird.

Optimieren

Es gibt mehrere Möglichkeiten, die Setgröße zu kürzen:

  1. Benutzerdefinierte Sortiermethode schreiben, anstatt eine Bibliothek eines Drittanbieters zu importieren
  2. Mit der integrierten Methode Array.prototype.sort() können Sie numerisch sortieren
  3. Nur die sortBy-Methode aus lodash und nicht die gesamte Bibliothek importieren
  4. Code zum Sortieren nur dann herunterladen, wenn der Nutzer auf die Schaltfläche klickt

Die Optionen 1 und 2 sind perfekt geeignete Methoden zum Reduzieren der Bundle-Größe (und sind wahrscheinlich für eine echte Anwendung am sinnvollsten). Sie werden in dieser Anleitung jedoch nicht zum Unterrichten verwendet 😈.

Beide Optionen tragen zur Leistungsverbesserung dieser Anwendung bei. Diese Schritte werden in den nächsten Abschnitten dieses Codelab beschrieben. Wie bei jeder Programmieranleitung sollten Sie immer versuchen, den Code selbst zu schreiben, anstatt ihn zu kopieren und einzufügen.

Nur Daten importieren, die Sie benötigen

Es müssen einige Dateien geändert werden, um nur die eine Methode aus lodash zu importieren. Ersetzen Sie zuerst diese Abhängigkeit in package.json:

"lodash": "^4.7.0",

damit:

"lodash.sortby": "^4.7.0",

Importieren Sie jetzt in src/index.js dieses Modul:

import "./style.css";
import _ from "lodash";
import sortBy from "lodash.sortby";

Aktualisieren Sie die Sortierung der Werte:

form.addEventListener("submit", e => {
  e.preventDefault();
  const values = [input1.valueAsNumber, input2.valueAsNumber, input3.valueAsNumber];
  const sortedValues = _.sortBy(values);
  const sortedValues = sortBy(values);

  results.innerHTML = `
    <h2>
      ${sortedValues}
    </h2>
  `
});

Aktualisieren Sie die Anwendung, öffnen Sie die Entwicklertools und sehen Sie sich noch einmal den Bereich Netzwerk an.

Netzwerkbereich mit einem 15,2 KB großen JavaScript-Bundle.

Für diese Anwendung konnte die Bundle-Größe mit sehr geringem Aufwand um mehr als das Vierfache reduziert werden, aber es gibt noch mehr Raum für Verbesserungen.

Codeaufteilung

webpack ist eines der beliebtesten Open-Source-Modul-Bundler, die derzeit verwendet werden. Kurz gesagt: Alle JavaScript-Module (sowie andere Assets), aus denen eine Webanwendung besteht, werden in statischen Dateien gebündelt, die vom Browser gelesen werden können.

Das in dieser Anwendung verwendete Bundle kann in zwei separate Blöcke unterteilt werden:

  • Einer ist für den Code verantwortlich, der unsere ursprüngliche Route ausmacht.
  • Ein sekundärer Block, der unseren Sortiercode enthält

Mit dynamischen Importen kann ein sekundärer Block Lazy Loading oder on demand geladen werden. In dieser Anwendung kann der Code, aus dem der Block besteht, nur geladen werden, wenn der Nutzer die Schaltfläche drückt.

Entfernen Sie zuerst den Import der obersten Ebene für die Sortiermethode in src/index.js:

import sortBy from "lodash.sortby";

Importieren Sie ihn in den Event-Listener, der ausgelöst wird, wenn auf die Schaltfläche geklickt wird:

form.addEventListener("submit", e => {
  e.preventDefault();
  import('lodash.sortby')
    .then(module => module.default)
    .then(sortInput())
    .catch(err => { alert(err) });
});

Die Funktion import() ist Teil eines Angebots (derzeit in Phase 3 des TC39-Prozesses), um die Möglichkeit zum dynamischen Importieren eines Moduls zu bieten. Webpack unterstützt diese bereits und folgt derselben Syntax wie im Angebot festgelegt.

import() gibt ein Promise zurück. Wenn es aufgelöst wird, wird das ausgewählte Modul bereitgestellt, das in einen separaten Chunk aufgeteilt wird. Nachdem das Modul zurückgegeben wurde, wird mit module.default auf den von lodash bereitgestellten Standardexport verwiesen. Das Promise ist mit einer anderen .then verkettet, die eine sortInput-Methode aufruft, um die drei Eingabewerte zu sortieren. Am Ende der Promise-Kettecatch() wird für Fälle verwendet, in denen das Promise aufgrund eines Fehlers abgelehnt wird.

Als Letztes müssen Sie noch die Methode sortInput am Ende der Datei schreiben. Dies muss eine Funktion sein, die eine Funktion zurückgibt, die die importierte Methode aus lodash.sortBy annimmt. Die verschachtelte Funktion kann dann die drei Eingabewerte sortieren und das DOM aktualisieren.

const sortInput = () => {
  return (sortBy) => {
    const values = [
      input1.valueAsNumber,
      input2.valueAsNumber,
      input3.valueAsNumber
    ];
    const sortedValues = sortBy(values);

    results.innerHTML = `
      <h2>
        ${sortedValues}
      </h2>
    `
  };
}

Überwachen

Aktualisieren Sie die Anwendung ein letztes Mal und prüfen Sie noch einmal den Bereich Netzwerk. Beim Laden der Anwendung wird nur ein kleines erstes Bundle heruntergeladen.

Netzwerkbereich mit einem 2,7 KB großen JavaScript-Bundle.

Nachdem die Schaltfläche zum Sortieren der Eingabenummern gedrückt wurde, wird der Block mit dem Sortiercode abgerufen und ausgeführt.

Netzwerkbereich mit einem 2,7 KB JavaScript-Bundle gefolgt von einem 13,9 KB großen JavaScript-Bundle.

Beachten Sie, wie die Zahlen trotzdem sortiert werden!

Fazit

Codeaufteilung und Lazy Loading können äußerst nützliche Techniken zur Reduzierung der anfänglichen Bundle-Größe Ihrer Anwendung sein. Dies kann direkt zu deutlich kürzeren Seitenladezeiten führen. Bevor Sie diese Optimierung in Ihre Anwendung übernehmen, müssen Sie jedoch einige wichtige Punkte berücksichtigen.

Lazy Loading-Benutzeroberfläche

Beim Lazy Loading bestimmter Codemodule sollten Sie sich überlegen, wie das für Nutzer mit schwächeren Netzwerkverbindungen aussehen würde. Das Aufteilen und Laden eines sehr großen Code-Chunks, wenn ein Nutzer eine Aktion sendet, kann den Anschein erwecken, dass die Anwendung nicht mehr funktioniert. Daher sollten Sie gegebenenfalls eine Ladeanzeige einblenden.

Lazy Loading von Drittanbieter-Knotenmodulen

Es ist nicht immer der beste Ansatz für Lazy Load von Abhängigkeiten von Drittanbietern in Ihrer Anwendung und hängt davon ab, wo Sie sie verwenden. Normalerweise werden Abhängigkeiten von Drittanbietern in ein separates vendor-Bundle aufgeteilt, das im Cache gespeichert werden kann, da sie nicht so oft aktualisiert werden. SplitChunksPlugin kann Ihnen dabei helfen.

Lazy Loading mit einem JavaScript-Framework

Viele gängige Frameworks und Bibliotheken, die Webpack verwenden, bieten Abstraktionen, um Lazy Loading einfacher zu machen als dynamische Importe in der Mitte Ihrer Anwendung.

Obwohl es hilfreich ist, die Funktionsweise dynamischer Importe zu verstehen, sollten Sie immer die von Ihrem Framework/Bibliothek empfohlene Methode für Lazy Loading bestimmter Module verwenden.

Vorabladen und Prefetch

Nutzen Sie nach Möglichkeit Browserhinweise wie <link rel="preload"> oder <link rel="prefetch">, um wichtige Module noch schneller zu laden. Webpack unterstützt beide Hinweise durch die Verwendung von magischen Kommentaren in Importanweisungen. Dies wird unter Kritische Blöcke vorab laden ausführlicher erläutert.

Lazy Loading von mehr als nur Code

Bilder können einen wesentlichen Teil einer Anwendung ausmachen. Lazy Loading von Elementen, die sich „below the fold“ (mit Scrollen sichtbar) oder außerhalb des Darstellungsbereichs des Geräts befinden, kann eine Website beschleunigen. Weitere Informationen finden Sie im Lazysizes-Leitfaden.