„document.write()“ eingreifen

Hast du dich kürzlich in deiner Developer Console in Chrome über eine solche Warnung wie die folgende informiert und dich gefragt, worum es sich dabei 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 Komponierbarkeit ist eine der großen Möglichkeiten des Webs. Sie ermöglicht uns die einfache Integration mit Diensten von Drittanbietern, um tolle neue Produkte zu entwickeln. Einer der Nachteile der Zusammensetzbarkeit besteht darin, dass eine gemeinsame Verantwortung für die Nutzererfahrung impliziert. Wenn die Integration nicht optimal ist, wird die Nutzererfahrung beeinträchtigt.

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

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

Bevor der Browser eine Seite rendern kann, muss er die DOM-Struktur durch Parsen des HTML-Markups erstellen. Immer wenn der Parser auf ein Skript stößt, muss er es beenden und ausführen, bevor er mit dem Parsen des HTML-Codes fortfahren kann. Wenn das Skript dynamisch ein anderes Skript einfügt, muss der Parser noch länger auf den Download der Ressource warten. Dies kann zu Netzwerk-Roundtrips und zu Verzögerungen beim ersten Rendern der Seite führen.

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

Wir haben Daten aus einem 28-tägigen Field Trial mit 1% der stabilen Chrome-Nutzer erhoben, die auf Nutzer mit 2G-Verbindungen beschränkt waren. Bei 7,6% aller Seitenaufrufe mit 2G war mindestens ein websiteübergreifendes Skript zum Blockieren von Parsern enthalten, das über document.write() in das übergeordnete Dokument eingefügt wurde. Nachdem das Laden dieser Skripts blockiert wurde, konnten wir bei diesen Ladevorgängen folgende Verbesserungen feststellen:

  • 10% mehr Seitenladevorgänge erreichen First Contentful Paint (eine visuelle Bestätigung für den Nutzer, dass die Seite effektiv geladen wird), 25% mehr Seitenladevorgänge erreichen den vollständig geparsten Status und 10% weniger Neuladevorgänge lassen die Frustration der Nutzer ab.
  • Um 21% kürzere durchschnittliche Zeit (mehr als eine Sekunde schneller) bis zum First Contentful Paint
  • Reduzierung der durchschnittlichen Zeit zum Parsen einer Seite um 38%. Dies entspricht einer Verbesserung von fast sechs Sekunden, wodurch die Zeit, die für die Anzeige von Inhalten benötigt wird, die dem Nutzer wichtig sind, drastisch reduziert wird.

Angesichts dieser Daten greift Chrome ab Version 55 im Namen aller Nutzer ein, wenn wir dieses bekannte fehlerhafte Muster erkennen, indem wir die Verarbeitung von document.write() in Chrome ändern (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 eine 2G-Verbindung nutzt. Zukünftig wird diese Änderung möglicherweise auch für andere Nutzer mit langsamen Verbindungen gelten, z. B. bei langsamem 3G oder langsamem WLAN.
  2. document.write() befindet sich in einem Dokument auf oberster Ebene. Die Maßnahme gilt nicht für document.writing-Skripts in iFrames, da diese das Rendering 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. Chrome greift also nicht bei Skripts mit einer übereinstimmenden eTLD+1 ein (z.B. ein auf js.example.org gehostetes Skript auf www.example.org).
  5. Das Skript befindet sich noch nicht im HTTP-Cache des Browsers. Skripts im Cache verursachen keine Netzwerkverzögerung und werden weiterhin ausgeführt.
  6. Bei der Anforderung 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.

Snippets von Drittanbietern 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 Inhalts auf der Seite zu blockieren.

Was kann ich tun?

Diese einfache Antwort lautet: Keine Skripts mit document.write() einfügen. Wir bieten eine Reihe von bekannten Diensten für die Unterstützung des asynchronen Ladeprogramms an, deren Überprüfung Sie sich immer wieder ansehen sollten.

Wenn Ihr Anbieter nicht auf der Liste steht und das asynchrone Laden von Skripts unterstützt, informieren Sie uns und wir können die Seite aktualisieren, um allen Nutzern zu helfen.

Wenn Ihr Anbieter das asynchrone Laden von Skripts in Ihre Seite nicht unterstützt, sollten Sie sich an ihn wenden und uns über die Auswirkungen informieren.

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

So erkennen Sie, ob Ihre Website betroffen ist

Ob die Einschränkung erzwungen wird, hängt von einer Vielzahl von 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. Mithilfe der Network Information API, die in Chrome verfügbar ist, können Sie den aktuellen Netzwerktyp und die Geschwindigkeit des Nutzers ermitteln und dann eine Warnmeldung an Ihre analytischen oder Real User Metrics (RUM) 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

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 zum Schreiben von Dokumenten.

Es ist toll, Warnungen in den Chrome-Entwicklertools zu sehen, aber wie lässt sich das erkennen? 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 Script blockiert wird, sendet Chrome 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 für das Skript gesendet (asynchron im Fall einer tatsächlichen Intervention).

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 haben wir in Chrome 53 nur eine Warnung in der Developer Console angezeigt. (Die Betaphase erfolgte im Juli 2016. Die stabile Version wird voraussichtlich im September 2016 für alle Nutzer verfügbar sein.

Wir werden eingreifen, um eingefügte Skripts für 2G-Nutzer vorläufig zu blockieren. Chrome 54 wird voraussichtlich ab Mitte Oktober 2016 in einer stabilen Version für alle Nutzer verfügbar sein. Weitere Informationen finden Sie im Chrome-Statuseintrag.

Mit der Zeit werden wir dann eingreifen, wenn ein Nutzer eine langsame Verbindung hat (z. B. langsames 3G oder WLAN). Folgen Sie diesem Chrome-Statuseintrag.

Möchtest du mehr erfahren?

Weitere Informationen finden Sie in diesen zusätzlichen Ressourcen: