Da wir immer mehr Websites erstellen, die stark auf JavaScript basieren, zahlen wir manchmal für das, was wir senden, auf eine Weise, die nicht immer leicht zu erkennen ist. In diesem Artikel erfahren Sie, warum ein wenig Disziplin hilfreich sein kann, wenn Sie möchten, dass Ihre Website auf Mobilgeräten schnell geladen wird und interaktiv ist. Wenn weniger JavaScript gesendet wird, kann das die Netzwerkübertragungszeit verkürzen, die Zeit für das Dekomprimieren von Code und das Parsen und Kompilieren dieses JavaScripts verringern.
Netzwerk
Wenn die meisten Entwickler an die Kosten von JavaScript denken, denken sie an die Kosten für den Download und die Ausführung. Je langsamer die Verbindung eines Nutzers ist, desto länger dauert es, mehr JavaScript-Byte über die Leitung zu senden.
Das kann ein Problem sein, da der effektive Netzwerkverbindungstyp eines Nutzers möglicherweise nicht 3G, 4G oder WLAN ist. Sie können sich im WLAN eines Cafés befinden, aber mit einem Mobilfunk-Hotspot mit 2G-Geschwindigkeit verbunden sein.
Sie können die Netzwerkübertragungskosten für JavaScript reduzieren, indem Sie:
- Nur den Code senden, den ein Nutzer benötigt
- Verwenden Sie die Codeaufteilung, um Ihren JavaScript-Code in kritische und nicht kritische Codeblöcke aufzuteilen. Modul-Bundler wie webpack unterstützen Code-Splitting.
- Laden nicht kritischer Code per Lazy Loading
- Minimierung
- Verwenden Sie UglifyJS, um ES5-Code zu minimieren.
- Verwenden Sie babel-minify oder uglify-es, um ES2015 und höher zu minimieren.
- Komprimierung
- Entfernen Sie nicht verwendeten Code.
- Mit der Codeabdeckung in den Entwicklertools können Sie Code identifizieren, der entfernt oder verzögert geladen werden kann.
- Verwende babel-preset-env und browserlist, um Funktionen zu vermeiden, die bereits in modernen Browsern vorhanden sind. Erfahrene Entwickler können mit einer sorgfältigen Analyse ihrer webpack-Bundles Möglichkeiten finden, unnötige Abhängigkeiten zu entfernen.
- Informationen zum Entfernen von Code finden Sie unter Tree-Shaking, den erweiterten Optimierungen des Closure Compilers und den Plug-ins zum Kürzen von Bibliotheken wie lodash-babel-plugin oder dem ContextReplacementPlugin von webpack für Bibliotheken wie Moment.js.
- Code im Cache speichern, um Netzwerkzugriffe zu minimieren
- Verwenden Sie HTTP-Caching, damit Browser Antworten effektiv im Cache speichern. Legen Sie die optimale Gültigkeitsdauer für Scripts (max-age) fest und geben Sie Validierungstokens (ETag) an, um die Übertragung unveränderter Bytes zu vermeiden.
- Mit dem Service Worker-Caching können Sie Ihr App-Netzwerk ausfallsicherer machen und sofort auf Funktionen wie den Codecache von V8 zugreifen.
- Verwenden Sie langfristiges Caching, um Ressourcen, die sich nicht geändert haben, nicht noch einmal abrufen zu müssen. Wenn Sie Webpack verwenden, lesen Sie den Hilfeartikel Dateinamen-Hash.
Parsen/Kompilieren
Nach dem Download ist eine der höchsten Kosten von JavaScript die Zeit, die eine JS-Engine benötigt, um diesen Code zu parsieren/kompilieren. In den Chrome-Entwicklertools sind „Parsen“ und „Kompilieren“ Teil der gelben Zeitspanne „Scripting“ im Bereich „Leistung“.
Auf den Tabs „Bottom-Up“ und „Aufrufbaum“ sehen Sie die genauen Parse-/Kompilierungszeiten:

Aber warum ist das wichtig?
Wenn das Parsen und Kompilieren von Code zu lange dauert, kann es sehr lange dauern, bis ein Nutzer mit Ihrer Website interagieren kann. Je mehr JavaScript Sie senden, desto länger dauert es, bis es geparst und kompiliert wurde und Ihre Website interaktiv ist.
Byte für Byte ist JavaScript für den Browser aufwendiger zu verarbeiten als ein Bild oder eine Webschrift mit derselben Größe. – Tom Dale
Im Vergleich zu JavaScript sind für die Verarbeitung von Bildern mit gleicher Größe zahlreiche Kosten verbunden (sie müssen immer noch decodiert werden!). Auf durchschnittlicher mobiler Hardware wirkt sich JS jedoch mit größerer Wahrscheinlichkeit negativ auf die Interaktivität einer Seite aus.

Wenn wir sagen, dass das Parsen und Kompilieren langsam ist, ist der Kontext wichtig. Wir sprechen hier von durchschnittlichen Smartphones. Die Smartphones der durchschnittlichen Nutzer können langsame CPUs und GPUs haben, keinen L2/L3-Cache und sogar Speichereinschränkungen aufweisen.
Netzwerkfunktionen und Gerätefunktionen stimmen nicht immer überein. Ein Nutzer mit einer hervorragenden Glasfaserverbindung hat nicht unbedingt die beste CPU, um an sein Gerät gesendetes JavaScript zu parsen und zu bewerten. Das gilt auch umgekehrt: eine schlechte Netzwerkverbindung, aber eine blitzschnelle CPU. – Kristofer Baxter, LinkedIn
Unten sehen Sie die Kosten für das Parsen von etwa 1 MB dekomprimierten (einfachen) JavaScripts auf Low-End- und High-End-Hardware. Die Zeit zum Parsen/Kompilieren von Code ist bei den schnellsten Smartphones auf dem Markt 2- bis 5-mal kürzer als bei durchschnittlichen Smartphones.

Wie sieht es mit einer echten Website aus, z. B. CNN.com?
Auf dem High-End-Smartphone iPhone 8 dauert das Parsen/Kompilieren des JS-Codes von CNN nur etwa 4 Sekunden, auf einem durchschnittlichen Smartphone (Moto G4) etwa 13 Sekunden. Das kann sich erheblich darauf auswirken, wie schnell ein Nutzer vollständig mit dieser Website interagieren kann.

Das unterstreicht die Bedeutung von Tests auf durchschnittlicher Hardware (wie dem Moto G4) und nicht nur auf dem Smartphone, das sich gerade in Ihrer Tasche befindet. Der Kontext ist jedoch wichtig: Optimieren Sie die Inhalte für die Geräte- und Netzwerkbedingungen Ihrer Nutzer.

Senden wir wirklich zu viel JavaScript? Möglicherweise. :)
Bei der Analyse des Zustands von JavaScript auf Mobilgeräten mithilfe des HTTP-Archivs (die 500.000 wichtigsten Websites) haben wir festgestellt, dass 50% der Websites mehr als 14 Sekunden benötigen, um interaktiv zu werden. Auf diesen Websites dauert das Parsen und Kompilieren von JavaScript bis zu vier Sekunden.
Wenn Sie die Zeit berücksichtigen, die zum Abrufen und Verarbeiten von JS und anderen Ressourcen benötigt wird, ist es vielleicht nicht überraschend, dass Nutzer eine Weile warten müssen, bis die Seiten einsatzbereit sind. Das können wir definitiv besser machen.
Wenn Sie nicht kritisches JavaScript von Ihren Seiten entfernen, können Sie die Übertragungszeiten, das CPU-intensive Parsen und Kompilieren sowie den potenziellen Arbeitsspeicher-Overhead reduzieren. Außerdem können Ihre Seiten so schneller interaktiv werden.
Ausführungszeit
Nicht nur das Parsen und Kompilieren kann Kosten verursachen. Die JavaScript-Ausführung (Ausführen von Code nach dem Parsen/Kompilieren) ist einer der Vorgänge, der im Hauptthread erfolgen muss. Lange Ausführungszeiten können auch dazu führen, dass Nutzer erst später mit Ihrer Website interagieren können.
Wenn das Script länger als 50 ms ausgeführt wird, wird die Zeit bis zur Interaktivität um die gesamte Zeit verzögert, die zum Herunterladen, Kompilieren und Ausführen des JS benötigt wird.
Um dies zu vermeiden, sollte JavaScript in kleinen Teilen vorliegen, um ein Blockieren des Hauptthreads zu verhindern. Prüfen Sie, ob Sie die Menge der Arbeit reduzieren können, die während der Ausführung ausgeführt wird.
Sonstige Kosten
JavaScript kann sich auch auf andere Weise auf die Seitenleistung auswirken:
- Arbeitsspeicher. Seiten können aufgrund der Garbage Collection (GC) häufig ruckeln oder anhalten. Wenn ein Browser Speicher zurückfordert, wird die JS-Ausführung pausiert. Ein Browser, der häufig Speicher bereinigt, kann die Ausführung also häufiger als gewünscht pausieren. Vermeiden Sie Speicherlecks und häufige GC-Pausen, damit Seiten flüssig laufen.
- Während der Laufzeit kann langlaufendes JavaScript den Hauptthread blockieren, was dazu führt, dass Seiten nicht mehr reagieren. Wenn Sie die Arbeit in kleinere Teile aufteilen (mit
requestAnimationFrame()
oderrequestIdleCallback()
für die Planung), können Sie Probleme mit der Reaktionsfähigkeit minimieren und so den Messwert „Interaction to Next Paint“ (INP) verbessern.
Muster zur Reduzierung der Kosten für die JavaScript-Auslieferung
Wenn Sie die Parse-/Kompilierungs- und Netzwerkübertragungszeiten für JavaScript niedrig halten möchten, gibt es hilfreiche Muster wie routenbasiertes Chunking oder PRPL.
PRPL
PRPL (Push, Render, Pre-cache, Lazy-load) ist ein Muster, das durch aggressives Code-Splitting und Caching für Interaktivität optimiert wird:
Sehen wir uns an, welche Auswirkungen das haben kann.
Wir analysieren die Ladezeit beliebter mobiler Websites und progressiver Web-Apps mithilfe der Laufzeitaufrufstatistiken von V8. Wie wir sehen, nimmt die Parsezeit (orange dargestellt) bei vielen dieser Websites einen erheblichen Teil in Anspruch:
Wego ist eine Website, die PRPL verwendet. Sie kann eine geringe Parsezeit für ihre Routen beibehalten und ist sehr schnell interaktiv. Viele der anderen oben genannten Websites haben Code-Splitting und Leistungsbudgets eingeführt, um ihre JS-Kosten zu senken.
Progressives Bootstrapping
Viele Websites optimieren die Sichtbarkeit von Inhalten auf Kosten der Interaktivität. Um bei großen JavaScript-Bundles eine schnelle erste Darstellung zu erzielen, verwenden Entwickler manchmal das serverseitige Rendering. Anschließend wird es „aufgerüstet“, um Ereignishandler anzuhängen, wenn das JavaScript schließlich abgerufen wird.
Achtung: Das hat jedoch einen Einfluss auf die Laufzeit. Sie senden 1) im Allgemeinen eine größere HTML-Antwort, was die Interaktivität beeinträchtigen kann, und 2) kann es zu einem unheimlichen Tal kommen, in dem die Hälfte der Website nicht interaktiv ist, bis die JavaScript-Verarbeitung abgeschlossen ist.
Progressives Bootstrapping ist möglicherweise ein besserer Ansatz. Senden Sie eine minimal funktionsfähige Seite, die nur aus dem für die aktuelle Route erforderlichen HTML-/JS-/CSS-Code besteht. Sobald weitere Ressourcen verfügbar sind, kann die App die Funktionen per Lazy-Load laden.

Der Code sollte proportional zum sichtbaren Inhalt geladen werden. PRPL und Progressives Bootstrapping sind Muster, die dabei helfen können.
Ergebnisse
Die Übertragungsgröße ist für Low-End-Netzwerke entscheidend. Die Parsezeit ist für CPU-gebundene Geräte wichtig. Es ist wichtig, diese niedrig zu halten.
Teams haben gute Erfahrungen mit strengen Leistungsbudgets gemacht, um die Übertragungs- und Parse-/Kompilierungszeiten von JavaScript niedrig zu halten. Sehen Sie sich das Video Can You Afford It?: Real-world Web Performance Budgets (Echtzeit-Budgets für die Webleistung) für Informationen zu Budgets für Mobilgeräte.

Wenn Sie eine Website für Mobilgeräte entwickeln, sollten Sie möglichst auf repräsentativer Hardware entwickeln, die JavaScript-Parse-/Kompilierungszeiten niedrig halten und ein Leistungsbudget festlegen, damit Ihr Team die JavaScript-Kosten im Blick behalten kann.
Weitere Informationen
- Chrome Dev Summit 2017 – Best Practices für modernes Laden
- Leistung beim Starten von JavaScript
- Solving the web performance crisis – Nolan Lawson
- Können Sie sich das leisten? Realistische Leistungsbudgets — Alex Russell
- Web-Frameworks und ‑Bibliotheken bewerten – Kristofer Baxter
- Ergebnisse der Cloudflare-Tests mit Brotli zur Komprimierung (Hinweis: Dynamische Brotli-Komprimierung mit höherer Qualität kann das erste Laden der Seite verzögern. Daher sollten Sie die Ergebnisse sorgfältig bewerten. Sie sollten sie stattdessen statisch komprimieren.)
- Performance Futures — Sam Saccone