„document.write()“ eingreifen

Hast du kürzlich eine Warnung wie die folgende in deiner Developer Console in Chrome gesehen und dich gefragt, um welche es sich handelt?

(index):34 A Parser-blocking, cross-origin script,
https://paul.kinlan.me/ad-inject.js, is invoked via document.write().
This may be blocked by the browser if the device has poor network connectivity.

Die Zusammensetzbarkeit ist eine der großen Möglichkeiten des Webs. Sie ermöglicht uns die einfache Einbindung in Dienste, die von Drittanbietern entwickelt wurden, um großartige neue Produkte zu entwickeln. Einer der Nachteile der Zusammensetzbarkeit besteht darin, dass sie eine gemeinsame Verantwortung für die Nutzererfahrung impliziert. Wenn die Integration nicht optimal ist, wirkt sich das negativ auf die Nutzererfahrung aus.

Eine bekannte Ursache für schlechte Leistung ist die Verwendung von document.write() innerhalb von Seiten, insbesondere solche, bei denen Skripts eingefügt werden. So harmlos das Folgende aussieht, kann es echte Probleme für die Nutzer verursachen.

document.write('<script src="https://example.com/ad-inject.js"></script>');

Bevor der Browser eine Seite rendern kann, muss er die DOM-Baumstruktur erstellen, indem er das HTML-Markup parst. Wenn der Parser auf ein Skript stößt, muss er es anhalten und ausführen, bevor er den HTML-Code weiter analysieren kann. Wenn das Skript dynamisch ein anderes Skript einschleust, wird der Parser gezwungen, noch länger auf den Download der Ressource zu warten. Dies kann einen oder mehrere Netzwerk-Roundtrips verursachen und die Zeit bis zum ersten Rendern der Seite verzögern.

Bei Nutzern mit langsamen Verbindungen wie 2G können externe Skripts, die dynamisch über document.write() eingeschleust werden, die Anzeige des Inhalts der Hauptseite um mehrere Sekunden verzögern oder dazu führen, dass Seiten entweder nicht geladen werden oder so lange dauern, dass der Nutzer aufgibt. Anhand der Instrumentierung in Chrome haben wir herausgefunden, dass Seiten mit über document.write() eingefügten Drittanbieterskripts bei 2G in der Regel doppelt so langsam geladen werden.

Wir haben im Rahmen eines 28-tägigen Field Trials bei 1% der stabilen Chrome-Nutzer Daten erhoben, die auf Nutzer mit 2G-Verbindungen beschränkt waren. Wir haben festgestellt, dass 7,6% aller Seitenladevorgänge bei 2G mindestens ein websiteübergreifendes Parser-Blocking-Skript enthielten, das über document.write() in das Dokument auf oberster Ebene eingefügt wurde. Durch das Blockieren der Last dieser Skripts haben wir folgende Verbesserungen festgestellt:

  • 10% mehr Seitenladevorgänge bis zum First Contentful Paint (eine visuelle Bestätigung für den Nutzer, dass die Seite erfolgreich geladen wird), 25% mehr Seitenladevorgänge, die den vollständig geparsten Zustand erreichen, und 10% weniger Neuladevorgänge, was auf eine geringere Frustration der Nutzer hindeutet.
  • 21% Verkürzung der durchschnittlichen Zeit (über eine Sekunde schneller) bis zum First Contentful Paint
  • Eine Reduzierung der durchschnittlichen Parsing-Zeit einer Seite um 38% entspricht einer Verbesserung von fast sechs Sekunden, wodurch die Anzeige von Inhalten, die für den Nutzer wichtig sind, drastisch reduziert wird.

Vor diesem Hintergrund interverfolgt Chrome ab Version 55 im Namen aller Nutzer, wenn dieses bekannte schlechte Muster erkannt wird, indem die Verarbeitung von document.write() in Chrome geändert wird (siehe Chrome-Status). Insbesondere führt Chrome die über document.write() eingeschleusten <script>-Elemente nicht aus, wenn alle der folgenden Bedingungen erfüllt sind:

  1. Der Nutzer hat eine langsame Verbindung, insbesondere wenn er 2G verwendet. Zukünftig wird die Änderung möglicherweise auch auf andere Nutzer mit langsamen Verbindungen wie langsamem 3G oder langsamem WLAN ausgeweitet.
  2. Die Datei document.write() befindet sich in einem Dokument auf oberster Ebene. Dies gilt nicht für „document.Writing“-Scripts in iFrames, da diese das Rendern der Hauptseite nicht blockieren.
  3. Das Skript im document.write() blockiert den Parser. Skripts mit den Attributen async oder defer werden weiterhin ausgeführt.
  4. Das Skript wird nicht auf derselben Website gehostet. Anders ausgedrückt: Bei Skripts mit einer übereinstimmenden eTLD+1 (z.B. ein unter js.example.org gehostetes Skript auf www.example.org) greift Chrome nicht ein.
  5. Das Skript befindet sich nicht bereits im HTTP-Cache des Browsers. Skripts im Cache verursachen keine Netzwerkverzögerung und werden trotzdem ausgeführt.
  6. Bei der Anfrage für die Seite handelt es sich nicht um eine Aktualisierung. Chrome greift nicht ein, wenn der Nutzer eine Aktualisierung ausgelöst hat, und führt die Seite wie gewohnt aus.

Drittanbieter-Snippets verwenden manchmal document.write(), um Skripts zu laden. Glücklicherweise bieten die meisten Drittanbieter asynchrone Ladealternativen an, mit denen Skripts von Drittanbietern geladen werden können, ohne die Anzeige des restlichen Seiteninhalts zu blockieren.

Was kann ich tun?

Diese einfache Antwort lautet: Fügen Sie keine Skripts mit document.write() ein. Es gibt eine Reihe von bekannten Diensten zur Unterstützung des asynchronen Loaders, die Sie immer wieder überprüfen sollten.

Wenn Ihr Anbieter nicht in der Liste aufgeführt ist und das asynchrone Laden von Skripts unterstützt, teilen Sie uns dies bitte mit, damit wir die Seite aktualisieren können, um allen Nutzern zu helfen.

Wenn Ihr Anbieter das asynchrone Laden von Skripts auf Ihrer Seite nicht unterstützt, sollten Sie sich mit ihm in Verbindung setzen und uns mitteilen, welche Auswirkungen die Änderung hat.

Wenn Sie von Ihrem Anbieter ein Snippet erhalten, das document.write() enthält, können Sie dem Skriptelement unter Umständen ein async-Attribut hinzufügen oder die Skriptelemente mit DOM API-Elementen wie document.appendChild() oder parentNode.insertBefore() hinzufügen.

So erkennen Sie, wann Ihre Website betroffen ist

Ob die Einschränkung erzwungen wird, hängt von vielen Kriterien ab. Woher wissen Sie also, ob Sie betroffen sind?

Erkennen, wenn ein Nutzer 2G verwendet

Um die möglichen Auswirkungen dieser Änderung zu verstehen, müssen Sie zuerst wissen, wie viele Ihrer Nutzer 2G verwenden werden. Sie können den aktuellen Netzwerktyp und die Geschwindigkeit des Nutzers mithilfe der in Chrome verfügbaren Network Information API ermitteln und dann eine Mitteilung an Ihr Analysesystem oder an Ihr RUM-System (Real User Metrics) senden.

if(navigator.connection &&
    navigator.connection.type === 'cellular' &&
    navigator.connection.downlinkMax <= 0.115) {
    // Notify your service to indicate that you might be affected by this restriction.
}

Warnungen in den Chrome-Entwicklertools abfangen

Seit Chrome 53 gibt die Entwicklertools Warnungen bei problematischen document.write()-Anweisungen aus. Wenn eine document.write()-Anfrage die Kriterien 2 bis 5 erfüllt (Chrome ignoriert die Verbindungskriterien beim Senden dieser Warnung), sieht die Warnung in etwa so aus:

Warnung beim Schreiben eines Dokuments.

Warnungen in den Chrome-Entwicklertools sind toll, aber wie erkennen Sie diese im großen Maßstab? Sie können nach HTTP-Headern suchen, die beim Eingreifen an Ihren Server gesendet werden.

HTTP-Header in der Skriptressource prüfen

Wenn ein über document.write eingefügtes Skript blockiert wurde, sendet Chrome den folgenden Header an die angeforderte Ressource:

Intervention: <https://shorturl/relevant/spec>;

Wenn ein über document.write eingefügtes Skript gefunden wird und unter verschiedenen Umständen blockiert werden könnte, sendet Chrome möglicherweise Folgendes:

Intervention: <https://shorturl/relevant/spec>; level="warning"

Der Interventionsheader wird als Teil der GET-Anfrage an das Skript gesendet (asynchron für den Fall einer tatsächlichen Eingriffe).

Was wird die Zukunft bringen?

Der erste Plan besteht darin, diese Maßnahme auszuführen, wenn wir feststellen, dass die Kriterien erfüllt sind. Zunächst wurde in der Developer Console in Chrome 53 nur eine Warnung angezeigt. Die Betaversion wurde im Juli 2016 eingeführt. Die stabile Version wird voraussichtlich ab September 2016 für alle Nutzer verfügbar sein.

Wir werden die Einschleusung von Skripts für 2G-Nutzer vorerst ab Chrome 54 blockieren, der voraussichtlich Mitte Oktober 2016 in einer stabilen Version für alle Nutzer verfügbar sein wird. Weitere Updates finden Sie im Chrome-Statuseintrag.

Im Laufe der Zeit versuchen wir, einzugreifen, wenn Nutzer eine langsame Verbindung haben, d. h. eine langsame 3G- oder WLAN-Verbindung. Folgen Sie diesem Eintrag zum Chrome-Status.

Möchtest du mehr erfahren?

Weitere Informationen finden Sie in diesen zusätzlichen Ressourcen: