Ingrijpen tegen document.write()

Heeft u onlangs een waarschuwing zoals de volgende gezien in uw ontwikkelaarsconsole in Chrome en vroeg u zich af wat deze 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.

Composabiliteit is een van de grote krachten van internet, waardoor we gemakkelijk kunnen integreren met diensten die door derden zijn gebouwd om geweldige 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, wordt de gebruikerservaring negatief beïnvloed.

Een bekende oorzaak van slechte prestaties is het gebruik van document.write() binnen pagina's, met name bij toepassingen waarbij scripts worden geïnjecteerd. Hoe onschadelijk het volgende ook lijkt, 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 deze de DOM-boom opbouwen door de HTML-opmaak te parseren. Telkens wanneer de parser een script tegenkomt, moet hij het stoppen en uitvoeren voordat hij door kan gaan met het parseren van de HTML. Als het script dynamisch een ander script injecteert, wordt de parser gedwongen nog langer te wachten totdat de bron is gedownload, wat een of meer netwerkrondreizen kan veroorzaken en de tijd tot de eerste weergave van de pagina kan vertragen.

Voor gebruikers met langzame verbindingen, zoals 2G, kunnen externe scripts die dynamisch worden geïnjecteerd via document.write() de weergave van de inhoud van de hoofdpagina tientallen seconden vertragen, of ervoor zorgen dat pagina's niet worden geladen of zo lang duren dat de gebruiker gewoon opgeeft omhoog. Op basis van instrumenten in Chrome hebben we geleerd dat pagina's met scripts van derden die zijn ingevoegd via document.write() doorgaans twee keer zo langzaam worden geladen dan andere pagina's op 2G.

We hebben gegevens verzameld uit een praktijkproef van 28 dagen bij 1% van de stabiele Chrome-gebruikers, beperkt tot gebruikers met 2G-verbindingen. We zagen dat 7,6% van alle paginaladingen op 2G ten minste één cross-site, parser-blokkerend script bevatte dat via document.write() in het document op het hoogste niveau was ingevoegd. Als gevolg van het blokkeren van het laden van deze scripts hebben we de volgende verbeteringen bij het laden gezien:

  • 10% meer paginaladingen bereiken de eerste inhoudsvolle verf (een visuele bevestiging voor de gebruiker dat de pagina effectief wordt geladen), 25% meer paginaladingen bereiken de volledig geparseerde status en 10% minder herlaadbeurten, wat duidt op een afname van de frustratie van de gebruiker.
  • 21% afname van de gemiddelde tijd (ruim een ​​seconde sneller) tot de eerste tevreden verf
  • Een vermindering van 38% van de gemiddelde tijd die nodig is om een ​​pagina te parseren, wat neerkomt op een verbetering van bijna zes seconden, waardoor de tijd die nodig is om weer te geven wat voor de gebruiker belangrijk is, dramatisch wordt verkort.

Met deze gegevens in gedachten komt Chrome, vanaf versie 55, tussenbeide namens alle gebruikers wanneer we dit bekende slechte patroon detecteren door de manier te wijzigen waarop document.write() in Chrome wordt verwerkt (zie Chrome-status ). Chrome zal met name de <script> -elementen die zijn geïnjecteerd via document.write() niet uitvoeren als aan alle volgende voorwaarden is voldaan:

  1. De gebruiker heeft een trage verbinding, vooral wanneer de gebruiker 2G gebruikt. (In de toekomst kan de wijziging worden uitgebreid naar andere gebruikers met trage verbindingen, zoals trage 3G of trage WiFi.)
  2. document.write() bevindt zich in een document op het hoogste niveau. De interventie is niet van toepassing op document.write-scripts binnen iframes, aangezien deze de weergave van de hoofdpagina niet blokkeren.
  3. Het script in document.write() is parser-blokkerend. Scripts met de kenmerken ' async ' of ' defer ' worden nog steeds uitgevoerd.
  4. Het script wordt niet op dezelfde site gehost. Met andere woorden, Chrome zal niet ingrijpen bij scripts met een overeenkomende eTLD+1 (bijvoorbeeld een script dat wordt gehost op js.example.org en is ingevoegd op www.example.org).
  5. Het script bevindt zich nog niet in de HTTP-cache van de browser. Scripts in de cache ondervinden geen netwerkvertraging en worden nog steeds uitgevoerd.
  6. Het verzoek om de pagina is geen herladen. Chrome komt niet tussenbeide als de gebruiker een herlaadactie activeert en voert de pagina zoals normaal uit.

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

Hoe kan ik dit oplossen?

Dit eenvoudige antwoord is: injecteer geen scripts met document.write() . We onderhouden een reeks bekende services voor ondersteuning van asynchrone laders , waarvan we u aanraden deze te blijven controleren.

Als uw provider niet op de lijst staat en het asynchrone laden van scripts ondersteunt , laat het ons dan weten, zodat we de pagina kunnen bijwerken om alle gebruikers te helpen.

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

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

Hoe u kunt detecteren wanneer uw site is getroffen

Er zijn een groot aantal criteria die bepalen of de beperking wordt gehandhaafd, dus hoe weet u of u hierdoor wordt getroffen?

Detecteren wanneer een gebruiker 2G gebruikt

Om de potentiële impact van deze verandering te begrijpen, moet u eerst weten hoeveel van uw gebruikers gebruik zullen maken van 2G. U kunt het huidige netwerktype en de snelheid van de gebruiker detecteren met behulp van de Network Information API die beschikbaar is in Chrome en vervolgens een waarschuwing sturen naar uw analytische 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.
}

Vang waarschuwingen op in Chrome DevTools

Sinds Chrome 53 geeft DevTools waarschuwingen voor problematische document.write() -instructies. Als een document.write() -verzoek voldoet aan de 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 schrijven van document.

Waarschuwingen zien in Chrome DevTools is geweldig, maar hoe kun je dit op grote schaal detecteren? U kunt controleren of er HTTP-headers naar uw server worden verzonden wanneer de interventie plaatsvindt.

Controleer uw HTTP-headers op de scriptbron

Wanneer een via document.write ingevoegd script wordt geblokkeerd, stuurt Chrome de volgende header naar de gevraagde bron:

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

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

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

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

Wat brengt de toekomst?

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

We zullen tussenbeide komen om geïnjecteerde scripts voor 2G-gebruikers voorlopig te blokkeren, te beginnen in Chrome 54, waarvan naar verwachting medio oktober 2016 een stabiele release voor alle gebruikers beschikbaar zal zijn. Bekijk de Chrome-status voor meer updates.

Na verloop van tijd proberen we in te grijpen wanneer een gebruiker een trage verbinding heeft (dat wil zeggen, trage 3G of WiFi). Volg dit Chrome-statusitem .

Wilt u meer weten?

Raadpleeg deze aanvullende bronnen voor meer informatie: