„document.write()“ eingreifen

Haben Sie in letzter Zeit in der Developer Console in Chrome eine Warnung wie die folgende gesehen und sich gefragt, was das bedeutet?

(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 Kombinierbarkeit ist eine der großen Stärken des Webs. So können wir Drittanbieterdienste ganz einfach integrieren, um tolle neue Produkte zu entwickeln. Einer der Nachteile der Komponentenausrichtung besteht darin, dass sie eine gemeinsame Verantwortung für die Nutzerfreundlichkeit impliziert. Eine suboptimale Integration wirkt sich negativ auf die Nutzerfreundlichkeit aus.

Eine bekannte Ursache für eine schlechte Leistung ist die Verwendung von document.write() auf Seiten, insbesondere bei der Einschleusung von Scripts. 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 den DOM-Baum erstellen, indem er das HTML-Markup analysiert. Wenn der Parser auf ein Script stößt, muss er anhalten und es ausführen, bevor er mit dem Parsen der HTML-Datei fortfahren 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 einige 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 Drittanbieter-Skripts in der Regel doppelt so langsam geladen werden wie andere 2G-Seiten.

Wir haben Daten aus einem 28-tägigen Feldtest mit 1 % der Chrome Stable-Nutzer erhoben, die nur Nutzer mit 2G-Verbindungen umfasste. 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 des Ladens dieser Scripts konnten wir folgende Verbesserungen erzielen:

  • 10 % mehr Seitenladevorgänge, bei denen der First Contentful Paint (eine visuelle Bestätigung für den Nutzer, dass die Seite effektiv geladen wird) erreicht wird, 25 % mehr Seitenladevorgänge, bei denen der vollständig geparste Status erreicht wird, und 10 % weniger Neustarts, was auf eine geringere Frustration der Nutzer hindeutet.
  • Reduzierung der durchschnittlichen Zeit bis zur ersten Darstellung von Inhalt um 21 % (über eine Sekunde schneller)
  • Die durchschnittliche Zeit für das Parsen einer Seite konnte um 38 % reduziert werden, was einer Verbesserung von fast sechs Sekunden entspricht. Die Zeit, die vergeht, bis die für den Nutzer wichtigen Informationen angezeigt werden, wurde dadurch drastisch verkürzt.

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). Chrome führt die über document.write() eingeschleusten <script>-Elemente insbesondere 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. Diese Maßnahme gilt nicht für „document.writing“-Skripts in iFrames, da diese das Rendern der Hauptseite nicht blockieren.
  3. Das Script in document.write() blockiert den Parser. Scripts mit den Attributen async oder defer werden weiterhin ausgeführt.
  4. Das Skript wird nicht auf derselben Website gehostet. Mit anderen Worten: Chrome greift nicht bei Scripts mit einem übereinstimmenden eTLD+1 ein (z.B. ein Script, das auf js.beispiel.de gehostet und auf www.beispiel.org eingefügt wurde).
  5. Das Script befindet sich nicht bereits im HTTP-Cache des Browsers. Skripts im Cache verursachen keine Netzwerkverzögerung und werden trotzdem ausgeführt.
  6. Die Anfrage für die Seite ist kein Neuladen. Chrome greift nicht ein, wenn der Nutzer eine Aktualisierung ausgelöst hat, und führt die Seite wie gewohnt aus.

In Snippets von Drittanbietern wird manchmal document.write() zum Laden von Scripts verwendet. Glücklicherweise bieten die meisten Drittanbieter alternative asynchrone Lademethoden an, mit denen Drittanbieter-Scripts geladen werden können, ohne dass die Anzeige des restlichen Inhalts auf der Seite blockiert wird.

Wie kann ich das beheben?

Die einfache Antwort lautet: Scripts nicht mit document.write() einschleusen. Wir pflegen eine Reihe von bekannten Diensten für die Unterstützung asynchroner Loader, die Sie regelmäßig prüfen sollten.

Wenn Ihr Anbieter nicht in der Liste aufgeführt ist, aber das asynchrone Script-Laden unterstützt, teilen Sie uns das bitte mit, damit wir die Seite aktualisieren können.

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 dein Anbieter dir ein Snippet mit document.write() zur Verfügung stellt, kannst du dem Script-Element möglicherweise das Attribut async hinzufügen oder die Script-Elemente mit DOM-APIs wie document.appendChild() oder parentNode.insertBefore() hinzufügen.

So erkennen Sie, wann Ihre Website betroffen ist

Es gibt eine große Anzahl von Kriterien, die bestimmen, ob die Einschränkung angewendet wird. Woher wissen Sie also, ob Sie betroffen sind?

Erkennen, wenn ein Nutzer 2G nutzt

Um die potenziellen Auswirkungen dieser Änderung zu verstehen, müssen Sie zuerst wissen, wie viele Ihrer Nutzer 2G nutzen. Mit der Network Information API, die in Chrome verfügbar ist, können Sie den aktuellen Netzwerktyp und die aktuelle Netzwerkgeschwindigkeit des Nutzers ermitteln und dann eine Benachrichtigung an Ihre Analyse- oder RUM-Systeme (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 werden in den Entwicklertools Warnungen für problematische document.write()-Anweisungen ausgegeben. Wenn eine document.write()-Anfrage die Kriterien 2 bis 5 erfüllt (Chrome ignoriert die Verbindungskriterien beim Senden dieser Warnung), sieht sie in etwa so aus:

Warnung beim Schreiben von Dokumenten

Es ist zwar hilfreich, Warnungen in den Chrome-Entwicklertools zu sehen, aber wie können Sie diese Probleme in großem Umfang erkennen? Sie können nach HTTP-Headern suchen, die an Ihren Server gesendet werden, wenn die Intervention erfolgt.

HTTP-Header der Scriptressource prüfen

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

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

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

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

Der Header für die Intervention wird als Teil der GET-Anfrage für das Script gesendet (bei einer tatsächlichen Intervention asynchron).

Was wird die Zukunft bringen?

Der ursprüngliche Plan sieht vor, diese Maßnahme auszuführen, wenn wir feststellen, dass die Kriterien erfüllt sind. In Chrome 53 wurde in der Entwicklerkonsole nur eine Warnung angezeigt. (Die Betaphase begann im Juli 2016. Wir gehen davon aus, dass die Stable-Version im September 2016 für alle Nutzer verfügbar sein wird.)

Wir werden eingreifen, um eingeschleuste Scripts für 2G-Nutzer voraussichtlich ab Chrome 54 zu blockieren. Diese Version wird voraussichtlich Mitte Oktober 2016 als stabile Version für alle Nutzer veröffentlicht. Weitere Updates finden Sie im Chrome-Statuseintrag.

Mit der Zeit möchten wir eingreifen, wenn ein Nutzer eine langsame Verbindung hat (z. B. eine langsame 3G- oder WLAN-Verbindung). Folgen Sie diesem Eintrag zum Chrome-Status.

Möchten Sie mehr erfahren?

Weitere Informationen finden Sie in den folgenden Ressourcen: