Ingrijpen tegen document.write()

Hebt u onlangs een waarschuwing zoals hieronder in de ontwikkelaarsconsole van Chrome gezien en vroeg u zich af wat dit was?

(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.

Composability is een van de grote krachten van het web. Het stelt ons in staat om eenvoudig te integreren met diensten van derden om fantastische nieuwe producten te bouwen! Een van de nadelen van composability is dat het een gedeelde verantwoordelijkheid voor de gebruikerservaring impliceert. Als de integratie niet optimaal is, zal de gebruikerservaring negatief worden beïnvloed.

Een bekende oorzaak van slechte prestaties is het gebruik van document.write() in pagina's, met name die toepassingen die scripts injecteren. Hoe onschuldig het volgende er ook uitziet, het kan echte problemen voor gebruikers veroorzaken.

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

Voordat de browser een pagina kan weergeven, moet hij de DOM-boom opbouwen door de HTML-opmaak te parsen. Wanneer de parser een script tegenkomt, moet hij dit stoppen en uitvoeren voordat hij verder kan gaan met het parsen van de HTML. Als het script dynamisch een ander script injecteert, moet de parser nog langer wachten op het downloaden van de bron, wat kan leiden tot een of meer netwerkrondreizen en de tijd tot de eerste weergave van de pagina kan vertragen.

Voor gebruikers met trage verbindingen, zoals 2G, kunnen externe scripts die dynamisch worden ingevoegd via document.write() de weergave van de inhoud van de hoofdpagina tientallen seconden vertragen, of ervoor zorgen dat pagina's niet laden of zo lang duren dat de gebruiker het gewoon opgeeft. Op basis van instrumentatie in Chrome hebben we ontdekt dat pagina's met scripts van derden die zijn ingevoegd via document.write() doorgaans twee keer zo langzaam laden als andere pagina's op 2G.

We verzamelden gegevens uit een 28 dagen durende veldtest onder 1% van de stabiele Chrome-gebruikers, beperkt tot gebruikers met een 2G-verbinding. We zagen dat 7,6% van alle pagina's die op 2G werden geladen, ten minste één cross-site, parser-blokkerend script bevatte dat via document.write() in het hoofddocument was ingevoegd. Door het laden van deze scripts te blokkeren, zagen we de volgende verbeteringen:

  • 10% meer pagina's laden bij de first contentful paint (een visuele bevestiging voor de gebruiker dat de pagina daadwerkelijk wordt geladen), 25% meer pagina's laden bij de volledig geparseerde status en 10% minder herlaadbeurten, wat erop wijst dat er minder frustratie is bij de gebruiker.
  • 21% afname van de gemiddelde tijd (meer dan een seconde sneller) tot de eerste inhoudsvolle verf
  • De gemiddelde tijd die nodig is om een ​​pagina te parseren is met 38% verkort. Dit is een verbetering van bijna zes seconden. De tijd die nodig is om weer te geven wat voor de gebruiker van belang is, wordt hiermee drastisch verkort.

Met deze gegevens in gedachten grijpt Chrome, vanaf versie 55, namens alle gebruikers in wanneer we dit bekende, schadelijke patroon detecteren, door de manier waarop document.write() in Chrome wordt verwerkt te wijzigen (zie Chrome Status ). Chrome voert de via document.write() geïnjecteerde <script> -elementen specifiek niet uit wanneer aan alle volgende voorwaarden is voldaan:

  1. De gebruiker heeft een trage verbinding, met name wanneer hij/zij gebruikmaakt van 2G. (In de toekomst wordt deze wijziging mogelijk uitgebreid naar andere gebruikers met trage verbindingen, zoals trage 3G of trage wifi.)
  2. De document.write() bevindt zich in een document op het hoogste niveau. De ingreep is niet van toepassing op document.write-scripts binnen iframes, omdat deze de weergave van de hoofdpagina niet blokkeren.
  3. Het script in document.write() blokkeert de parser. Scripts met de kenmerken ' async ' of ' defer ' worden nog steeds uitgevoerd.
  4. Het script wordt niet op dezelfde site gehost. Met andere woorden, Chrome grijpt niet in voor scripts met een overeenkomende eTLD+1 (bijvoorbeeld een script dat gehost wordt op js.example.org en ingevoegd wordt op www.example.org).
  5. Het script staat nog niet in de HTTP-cache van de browser. Scripts in de cache veroorzaken geen netwerkvertraging en worden gewoon uitgevoerd.
  6. Het verzoek om de pagina te herladen is geen herladen. Chrome grijpt niet in als de gebruiker een herladen activeert en voert de pagina gewoon uit.

Snippets van derden gebruiken soms document.write() om scripts te laden. Gelukkig bieden de meeste derden asynchrone laadalternatieven , waarmee scripts van derden kunnen worden geladen zonder de weergave van de rest van de content op de pagina te blokkeren.

Hoe kan ik dit oplossen?

Dit simpele antwoord is: injecteer geen scripts met document.write() . We onderhouden een aantal bekende services voor asynchrone loaderondersteuning die we u aanraden regelmatig te bekijken.

Als uw provider niet in de lijst staat en wel asynchroon laden van scripts ondersteunt , laat het ons dan weten. We kunnen de pagina dan aanpassen om alle gebruikers te helpen.

Als uw provider de mogelijkheid om scripts asynchroon in uw pagina te laden niet ondersteunt, raden wij u aan contact met hen op te nemen en ons en hen te laten weten welke gevolgen dit voor hen heeft.

Als uw provider u een fragment levert dat document.write() bevat, kunt u mogelijk een async -kenmerk aan het scriptelement toevoegen. U kunt de scriptelementen ook toevoegen met DOM API's zoals document.appendChild() of parentNode.insertBefore() .

Hoe u kunt detecteren of uw site is getroffen

Er zijn veel criteria die bepalen of de beperking wordt gehandhaafd. Hoe weet u of dit op u van toepassing is?

Detecteren wanneer een gebruiker op 2G zit

Om de potentiële impact van deze wijziging te begrijpen, moet u eerst weten hoeveel van uw gebruikers 2G zullen gebruiken. U kunt het huidige netwerktype en de snelheid van de gebruiker detecteren met behulp van de Network Information API in Chrome en vervolgens een waarschuwing sturen naar uw analyse- of Real User Metrics (RUM)-systemen.

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.
}

Waarschuwingen opvangen in Chrome DevTools

Sinds Chrome 53 geeft DevTools waarschuwingen voor problematische document.write() instructies. Als een document.write() verzoek voldoet aan criteria 2 tot en met 5 (Chrome negeert de verbindingscriteria bij het verzenden van deze waarschuwing), ziet de waarschuwing er ongeveer zo uit:

Waarschuwing voor het schrijven van het document.

Waarschuwingen zien in Chrome DevTools is geweldig, maar hoe detecteer je dit op grote schaal? Je kunt controleren op HTTP-headers die naar je server worden verzonden wanneer de interventie plaatsvindt.

Controleer uw HTTP-headers op de scriptbron

Wanneer een via document.write ingevoegd script is geblokkeerd, zal Chrome de volgende header naar de opgevraagde bron sturen:

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

Wanneer een via document.write ingevoegd script wordt gevonden en onder verschillende omstandigheden kan worden geblokkeerd, kan Chrome het volgende versturen:

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

De interventieheader wordt verzonden als onderdeel van de GET-aanvraag voor het script (asynchroon in het geval van een daadwerkelijke interventie).

Wat brengt de toekomst?

Het eerste plan is om deze interventie uit te voeren wanneer we detecteren dat aan de criteria wordt voldaan. We begonnen met alleen een waarschuwing in de ontwikkelaarsconsole van Chrome 53. (Bètaversie was in juli 2016. We verwachten dat Stable in september 2016 voor alle gebruikers beschikbaar zal zijn.)

We zullen voorlopig ingrijpen om geïnjecteerde scripts voor 2G-gebruikers te blokkeren vanaf Chrome 54. Naar verwachting zal deze versie medio oktober 2016 voor alle gebruikers stabiel zijn. Bekijk de Chrome-status voor meer updates.

In de loop van de tijd willen we ingrijpen wanneer een gebruiker een trage verbinding heeft (bijvoorbeeld trage 3G of wifi). Volg deze Chrome-statusvermelding .

Wilt u meer weten?

Voor meer informatie kunt u de volgende aanvullende bronnen raadplegen: