Optimiere den Aufruf deiner Webseite mit Async und Defer

Wenn du deine Webseite schon einmal in Google Pagespeed Insights analysiert hast, wurde dir bestimmt schon folgende Verbesserung von Google vorgeschlagen:

Google Pagespeed - Ressourcen beseitigen die das Rendering blockieren

Ich erkläre dir, was der Hinweis "Ressourcen beseitigen, die das Rendering blockieren" bedeutet und wie du das Rendering deiner WordPress-Webseite verbesserst. Wenn du bereits weißt, was dieser Hinweis bedeutet, kannst du dir den PHP-Code für deine Webseite im letzten Teil des Beitrags "Ressourcen beseitigen die das Rendering blockieren in WordPress" kopieren. Über einen Kommentar würde ich mich sehr freuen, wenn du zufrieden mit dem Code-Schnipsel bist.

Was geschieht beim Aufruf einer Webseite?

Stelle dir vor, dein Webseiten-Besucher möchte deine Seite aufrufen. Dein Server sendet bei Erhalt der Anfrage die HTML-Datei, nachdem der PHP-Service alles vorbereitet hat. (Ich gehe mal bei dieser Annahme davon aus, dass du keinen Server-Cache installiert hast)

Nun analysiert der Browser die HTML-Datei und sucht alle externen Dateien, wie Bilder, CSS- und JavaScript-Dateien auf dem Server oder auf anderen Quellen heraus. Sofern der Besucher noch nicht auf deiner Seite war, hat er diese auch noch nicht in seinem Browser-Cache und muss diese beim Server einzeln anfragen.

Der Server sendet nun alle Dateien nacheinander an den Besucher. Nachdem die ersten Dateien beim Benutzer aufschlagen, fängt der Browser an das DOM zu vervollständigen und die Formatierungen auszuführen. Danach werden noch alle JavaScripte geladen, um auch die Dynamik zur Seite hinzuzufügen.

(Dieses Beispiel dient nur der Veranschaulichung. Das echte "abholen" von Dateien sieht ein wenig komplexer aus)

Du merkst jetzt wahrscheinlich, dass der Prozess sehr umfangreich ist, bis eine einzelne Seite vollständig geladen wurde. Gerade bei gekauften Templates auf Themeforest oder Andere, werden häufig sehr viele Stile und Skripte ausgeführt, die das erstmalige Rendering einer Webseite blockieren. Die Template-Hersteller wollen damit nichts böses bezwecken, sondern möglichst viele Anpassungsmöglichkeiten für deine Webseite zur Verfügung stellen.

Einfügen von Skripten in WordPress

Wenn du bereits ein wenig mit WordPress programmiert hast, kennst du wahrscheinlich die Funktion, um ein neues Skript in deine Webseite hinzuzufügen: wp_enqueue_script()

So könnte dein Code aussehen:

<?php
	function set_frontend_scripts() {
		wp_register_script( 'custom-script', get_template_directory_uri().'/js/custom.js', array( 'jquery' ) );
		wp_enqueue_script( 'custom-script' );
	}
	add_action( 'wp_enqueue_scripts', 'set_frontend_scripts' );
?>

Mit dieser Funktionen werden Scripte in den wp_head() Bereich geladen. Es können mehrere Einstellungen und Abhängigkeiten in den Parametern der Funktion hinterlegt werden. Jedoch keinen Parameter, um ein Skript nachzuladen zu lassen.

Skripte in HTML nachladen

Um ein Script in HTML nachzuladen, werden zum <script>-Tag die Attribute async und defer hinzugefügt.

Das Attribut "async" gibt an, dass ein Script "Asynchron" ausgeführt werden soll. Das bedeutet nicht, dass der Code in der Datei nacheinander ausgeführt wird, sondern dass der Code simultan mit beim Laden der Seite ausgeführt wird.

Das Attribut "defer" gibt an, dass der JavaScript-Code erst ausgeführt wird, wenn die Seite vollständig geladen wurde.

Sollten beide Attribute fehlen, wird der JavaScript sofort ausgeführt, wenn er geladen wurde. Der Rest des HTML-Codes wird geparst, sobald das JavaScript beendet wurde. Deshalb weißt Google immer darauf hin, dass der Analytics-Code am Ende der Seite vor dem schließenden <body>-Tag eingefügt werden soll.

Zudem solltest du beachten, dass die Attribute async und defer nur bei externen Ressourcen funktionieren. Also bei JavaScript-Dateien und nicht bei Inline-Skripten.

Der HTML-Code um ein Skript hinzuzufügen, dass nachgeladen werden soll, würde dann zum Beispiel so aussehen:

<script async="async" defer="defer" src="/js/custom.js"></script>

Ressourcen beseitigen die das Rendering blockieren in WordPress

Wie können wir es also anstellen, dass die Attribute defer und async zum wp_enqueue_script() hinzugefügt werden?

Die kurze Antwort: Über diese Funktion gar nicht.

Es gibt jedoch in WordPress einen Filter, mit dem Skripte geprüft und bearbeitet werden können, nachdem sie vom Template oder Plugins zur "Pipe" hinzugefügt wurden.

Mit dem script_loader_tag-Filter und einem str_replace() können wir den Output des Skripts nach belieben bearbeiten. Ich habe eine Funktion vorbereitet, die du für dein Projekt kopieren und anpassen kannst, um bestimmte Skripte mit den wertvollen defer- und async-Attributen zu versehen.

Aber vorsicht: Es kann sein, dass Skripte durch diese Angaben nicht mehr funktionieren. Teste am besten ein Skript nach dem anderen, ob deine JavaScripts die Attribute unterstützen. Im besten Fall verwendest du ein lokales Test-System, also eine Spiegelung deiner Webseite, auf der du verschiedene Sachen ausprobieren kannst.

Die nachfolgenden Code-Schnipsel kannst du in die functions.php deines Child-Themes hinzufügen, oder ein eigenes Plugin dafür erstellen.

Das Async-Attribut hinzufügen

<?php
	add_filter( 'script_loader_tag', 'add_async_attribute', 10, 2 );
	function add_async_attribute( $tag, $handle ) {
		$scripts_to_async = array( 'custom-script', 'another-script' );
		
		foreach( $scripts_to_async as $defer_script )
			if( $defer_script === $handle )
				return str_replace( ' src', ' async="async" src', $tag );
		
		return $tag;
	}
?>

Das Defer-Attribut hinzufügen

<?php
	add_filter( 'script_loader_tag', 'add_defer_attribute', 10, 2 );
	function add_defer_attribute( $tag, $handle ) {
		$scripts_to_defer = array( 'custom-script', 'another-script' );
		
		foreach( $scripts_to_defer as $defer_script )
			if( $defer_script === $handle )
				return str_replace( ' src', ' defer="defer" src', $tag );
		
		return $tag;
	}
?>

Kompatibilität des Codes

script_loader_tag Ab WordPress 4.1.0
str_replace() Ab PHP 4
async Ab HTML 4
Von allen modernen Browsern unterstützt:
Async auf CanIUse.com
defer Ab HTML 5
Von allen modernen Browsern unterstützt:
Defer auf CanIUse.com
 

Bevor du dieses Skript auf deiner Webseite einfügst, kannst du mit meinem Performance-Vergleich eine Analyse deiner Webseite starten. Wenn du das Ergebnis in deinem Browser sicherst, kannst du die Daten (Vorher und Nachher) besser miteinander vergleichen.

Nachdem dann deine Skripte mit Defer oder Async geladen werden, kannst du mit dem Performance-Vergleich einen weiteren Test durchführen. Du solltest feststellen, dass die Kategorie "Performance" einen besseren Wert als vor der Umsetzung hat.

Ein letzter Hinweis: Ich habe die Erfahrung gemacht, dass es besser ist jQuery nicht als Defer oder Async zu laden. Außerdem gibt es Templates, die keines der beiden Attribute zulassen. Du musst ein wenig testen, um herauszufinden ob die Attribute gesetzt werden können oder nicht.

 

Hast du schon Erfahrungen mit den Defer- und Async-Attributen gesammelt? Teile dein Wissen in den Kommentaren.

 

Codepalm
JavaScript in WordPress nachladen