Die häufigsten Empfehlungen für die Optimierung von JavaScript belaufen sich auf die Zusammenfassung aller Dateien, um die Anzahl an HTTP-Anfragen zu reduzieren, das Entfernen von unnötigen Inhalten und die Komprimierung der Übertragung. Mit der prallen Übertragung per HTTP/2 und der steigenden Bandbreite der Besucher spielen diese Faktoren allerdings keine so große Rolle mehr. Die Zeit zum Analysieren des JavaScript-Codes und die anschließende Ausführung sind bei vielen Seiten größer als die Ladezeit. Daher zeige ich hier verschiedene Methoden, wie die Geschwindigkeit der Website auch mit viel JavaScript optimiert werden kann.
Einbindung
Wird JavaScript ganz klassisch im Head-Bereich einer Website eingebunden, wird die Darstellung der Website erheblich verzögert. Der Webbrowser fängt mit der Analyse der Website an, findet die JavaScript-Datei, stoppt die weitere Analyse der HTML-Datei, lädt die JS-Datei herunter, führt sie anschließend aus und bearbeitet erst danach den Rest der HTML-Seite weiter. Um dies zu umgehen, wird die JavaScript-Datei ganz am Ende der Seite eingebunden. Alternativ kann die Einbindung wieder im Header in Kombination mit den Attributen async bzw. defer erfolgen, was den Ladevorgang sogar beschleunigt.
Mit async wird die JavaScript-Datei parallel geladen und nach dem Ladevorgang die Bearbeitung der HTML-Datei unterbrochen und die JavaScript-Datei interpretiert und ausgeführt. Anschließend wird die Bearbeitung der HTML-Seite vorgeführt.
Das Attribut defer sorgt dafür, dass der Webbrowser die JavaScript-Datei nur herunterlädt. Mit der Interpretation und Ausführung wird gewartet, bis die HTML-Seite fertig bearbeitet wurde. Dadurch kann die Java-Script Datei im Vergleich bis zur Einbindung ganz am Ende parallel geladen werden.
Flavio Copes hat das Verhalten in seinem Artikel „Efficiently load JavaScript with defer and async“ schön illustriert.
Laden bei Bedarf
Eine sehr effektive Methode, die Geschwindigkeit einer Website mit viel JavaScript zu erhöhen, ist das Laden bei Bedarf. Denn häufig werden bestimmte Funktionen nur auf einzelnen Seiten gebraucht und nicht alle direkt im sichtbaren Bereich. Daher sollte beim Seitenaufruf nur der notwendigste JavaScript-Teil geladen werden und dann bei Bedarf für einzelne Funktionen separate Dateien nachgeladen werden. Dazu wird überprüft werden, ob ein Element auf der Seite existiert und dann wird die entsprechende JavaScript-Datei nachgeladen werden.
Per jQuery lässt sich dieser Mechanismus sehr einfach realisieren. Als Erstes wird überprüft, ob das Element mit der ID existiert. Wenn dies der Fall ist, wird die Funktion getSrcipt() ausgeführt und die URL der JavaScript-Datei übergeben. Danach wird die Callback-Funktion ausgeführt, sobald die Datei erfolgreich geladen worden ist.
if($('#element').length){ $.getScript("script.js", function() { // callback }); }
Per reinem JavaScript kann die gleiche Funktion realisiert werden. Hier findet ebenfalls eine Überprüfung statt, ob das Element existiert. Anschließend wird ein neues Script-Element der Seite hinzugefügt und die Callback-Funktion ausgeführt, sobald die Datei geladen worden ist.
if(document.querySelector("#element")){ var script = document.createElement('script'); script.src = something; script.onload = function(){ // callback }; document.head.appendChild(script); }
Kompression
Um gut mit Code zu arbeiten, werden viele Umbrüche, Leerzeichen und Tabs eingefügt. Zusätzlich werden viele Abschnitte mit Kommentaren versehen, damit Entwickler sich besser zurechtfinden. Da die Elemente nicht beim Betrachten der Website benötigt werden, können diese entfernt werden. Die Zusammenfassung und Entfernung von unnötigen Inhalten sollten immer automatisiert nach einer Änderung an einer JavaScript-Datei erfolgen. Wird dieser Vorgang jedes Mal dynamisch bei einem Seitenaufruf ausgeführt, werden zu viele Serverressourcen benötigt und gleichzeitig nimmt der Prozess Zeit in Anspruch und verzögert dadurch den Seitenaufruf. Dieser Vorgang wird als minify bezeichnet und sollte immer ausgeführt werden.
Zusätzlich werden die JavaScript-Dateien bei der Übertragung komprimiert übertragen. Der Webserver übernimmt nach der Konfiguration automatisch das Packen und der Webbrowser entpackt sie wieder. Hier hat sich als Algorithmus gzip etabliert. Werden große JavaScript-Dateien eingesetzt, können diese vorab komprimiert und auf dem Webserver gespeichert werden. Dadurch können vor allem Seiten mit vielen Seitenaufrufen Zeit sparen.
Die Kompression per gzip kann beispielsweise per PHP erfolgen:
$script = file_get_contents('script.js'); file_put_contents('script.js.gz', gzencode($cript, 9, FORCE_GZIP));
Nachdem die Dateien als normale .js-Datei und zusätzliche als .js.gz-Datei abgelegt worden ist kann die Auslieferung per .htaccess-Datei konfiguriert werden. Dazu wird angegeben, dass alle .gz Dateien gzip komprimiert sind und Dateien mit der Endung *.js.gz JavaScript-Dateien sind. Eingebunden werden die Dateien normal mit .js-Dateiendung. In der .htaccess-Datei wird RewriteCond überprüft, ob der Webbrowser die gzip Komprimierung unterstützt. Ist dies der Fall, wird anstatt der .js-Datei die vorab komprimierte .js.gz-Datei ausgeliefert.
AddEncoding gzip .gzForceType application/javascript RewriteEngine on RewriteCond %{HTTP:Accept-encoding} gzip RewriteRule ^(.*)\.js$ $1.js.gz [QSA,L]
Fazit JavaScript Performance
Mit den vorgestellten Methoden kann die Geschwindigkeit der Website trotz größerem JavaScript-Anteil effizient optimiert werden. Gerade das Nachladen bei Bedarf kann die Geschwindigkeit enorm steigern, da der Webbrowser kein unnötiges JavaScript laden und verarbeiten muss. Das Speichern und Ausliefern von bereits vorab komprimierten Dateien spart vor allem bei Seiten mit vielen Besuchern Ressourcen.