Intervenire contro document.write()

Di recente hai visto un avviso simile al seguente nella Developer Console in Chrome e ti sei chiesto di cosa si trattasse?

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

La componibilità è uno dei grandi vantaggi del web, che ci consente di integrarci facilmente con servizi creati da terze parti per creare nuovi fantastici prodotti. Uno svantaggio della componibilità è che implica una responsabilità condivisa sull'esperienza utente. Se l'integrazione non è ottimale, l'esperienza utente ne risentirà.

Una causa nota delle prestazioni scadenti è l'utilizzo di document.write() all'interno delle pagine, in particolare degli usi che inseriscono gli script. Per quanto innocuo possa sembrare, può causare problemi reali agli utenti.

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

Prima che il browser possa eseguire il rendering di una pagina, deve creare la struttura DOM analizzando il markup HTML. Ogni volta che il parser rileva uno script, deve arrestarsi ed eseguirlo prima di poter continuare ad analizzare il codice HTML. Se lo script inserisce dinamicamente un altro script, il parser deve attendere ancora più tempo per il download della risorsa, il che può comportare uno o più roundtrip di rete e ritardare il primo rendering della pagina

Per gli utenti con connessioni lente, ad esempio 2G, gli script esterni inseriti dinamicamente tramite document.write() possono ritardare di decine di secondi la visualizzazione dei contenuti della pagina principale oppure causare il mancato caricamento delle pagine o un tempo così lungo da far sì che l'utente si rinunci. In base alla strumentazione in Chrome, abbiamo appreso che le pagine con script di terze parti inseriti tramite document.write() sono in genere due volte più lente a caricarsi rispetto ad altre pagine su 2G.

Abbiamo raccolto dati da una prova sul campo di 28 giorni sull'1% degli utenti stabili di Chrome, riservati agli utenti con connessioni 2G. Abbiamo notato che il 7, 6% di tutti i caricamenti di pagine su 2G includeva almeno uno script di blocco dell'analizzatore sintattico tra siti che è stato inserito tramite document.write() nel documento di primo livello. In seguito al blocco del caricamento di questi script, abbiamo riscontrato i seguenti miglioramenti:

  • 10% in più di caricamenti pagina che raggiungono la prima visualizzazione con contenuti (una conferma visiva all'utente che la pagina viene caricata correttamente), 25% di caricamenti pagina in più raggiungendo lo stato completamente analizzato e 10% di ricaricamenti in meno, il che indica una diminuzione della frustrazione dell'utente.
  • 21% di riduzione del tempo medio (oltre un secondo più veloce) fino alla prima visualizzazione con contenuti
  • 38% di riduzione del tempo medio necessario per analizzare una pagina, il che rappresenta un miglioramento di quasi sei secondi e una riduzione drastica del tempo necessario per mostrare ciò che conta per l'utente.

Tenendo presenti questi dati, Chrome, a partire dalla versione 55, interviene per conto di tutti gli utenti quando rileviamo questo pattern errato noto modificando la modalità di gestione di document.write() in Chrome (vedi Stato di Chrome). Nello specifico, Chrome non eseguirà gli elementi <script> inseriti tramite document.write() quando vengono soddisfatte tutte le seguenti condizioni:

  1. L'utente ha una connessione lenta, in particolare quando utilizza una rete 2G. In futuro, la modifica potrebbe essere estesa ad altri utenti con connessioni lente, come 3G o Wi-Fi lenti.
  2. document.write() si trova in un documento di primo livello. L'intervento non si applica agli script document.write all'interno di iframe, in quanto non bloccano il rendering della pagina principale.
  3. Lo script nell'document.write() sta bloccando l'analizzatore sintattico. Gli script con gli attributi "async" o "defer" continueranno a essere eseguiti.
  4. Lo script non è ospitato sullo stesso sito. In altre parole, Chrome non interverrà per gli script con un eTLD+1 corrispondente (ad esempio, uno script ospitato su js.example.org inserito su www.example.org).
  5. Lo script non si trova già nella cache HTTP del browser. Gli script nella cache non subiranno ritardi di rete e verranno comunque eseguiti.
  6. La richiesta per la pagina non viene ricaricata. Chrome non interverrà se l'utente ha attivato un ricaricamento e pubblicherà la pagina normalmente.

A volte gli snippet di terze parti utilizzano document.write() per caricare gli script. Fortunatamente, la maggior parte delle terze parti fornisce alternative di caricamento asincrono, che consentono il caricamento di script di terze parti senza bloccare la visualizzazione del resto dei contenuti sulla pagina.

Come faccio a risolvere il problema?

Questa semplice risposta è non inserire script utilizzando document.write(). Gestiamo una serie di servizi noti per il supporto del caricatore asincrono che ti invitiamo a continuare a controllare.

Se il tuo provider non è presente nell'elenco e supporta il caricamento di script asincrono, comunicacelo in modo da poter aggiornare la pagina per aiutare tutti gli utenti.

Se il tuo provider non supporta la possibilità di caricare in modo asincrono script nella pagina, ti invitiamo a contattarlo e comunicarci loro in che modo saranno interessati.

Se il tuo provider ti fornisce uno snippet che include document.write(), potresti aggiungere un attributo async all'elemento script o aggiungere gli elementi script con API DOM come document.appendChild() o parentNode.insertBefore().

Come rilevare quando il sito è interessato

Esistono molti criteri che determinano se la restrizione viene applicata, come fai a sapere se la modifica riguarda anche te?

Rilevare quando un utente è connesso a una rete 2G

Per comprendere il potenziale impatto di questa modifica, devi prima sapere quanti dei tuoi utenti utilizzeranno il 2G. Puoi rilevare il tipo e la velocità di rete attuali dell'utente utilizzando l'API Network Information disponibile in Chrome, quindi inviare un avviso ai sistemi di analisi o RUM (Real User Metrics).

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

Rilevare gli avvisi in Chrome DevTools

A partire da Chrome 53, DevTools invia avvisi per le istruzioni document.write() problematiche. In particolare, se una richiesta document.write() soddisfa i criteri da 2 a 5 (Chrome ignora i criteri di connessione quando invia questo avviso), l'avviso sarà simile a questo:

Avviso di scrittura documenti.

Vedere avvisi in Chrome DevTools è molto utile, ma come si rileva su larga scala? Puoi verificare le intestazioni HTTP inviate al tuo server quando viene eseguito l'intervento.

Controlla le intestazioni HTTP sulla risorsa script

Quando uno script inserito tramite document.write viene bloccato, Chrome invia la seguente intestazione alla risorsa richiesta:

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

Quando viene rilevato uno script inserito tramite document.write che potrebbe essere bloccato in diverse circostanze, Chrome potrebbe inviare:

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

L'intestazione dell'intervento verrà inviata come parte della richiesta GET per lo script (in modo asincrono in caso di intervento effettivo).

Che cosa ci riserva il futuro?

Il piano iniziale prevede di eseguire l'intervento quando rileviamo che i criteri sono stati soddisfatti. Abbiamo iniziato mostrando solo un avviso nella Developer Console in Chrome 53. La versione beta era a luglio 2016. Prevediamo che il canale stabile sarà disponibile per tutti gli utenti a settembre 2016.

Ci impegniamo a bloccare gli script inseriti per gli utenti 2G a partire da Chrome 54, che si stima sarà in versione stabile per tutti gli utenti a metà ottobre 2016. Consulta la voce sullo stato di Chrome per ulteriori aggiornamenti.

Nel corso del tempo, stiamo cercando di intervenire quando un utente ha una connessione lenta (ad esempio le connessione 3G o Wi-Fi lenta). Segui questa voce sullo stato di Chrome.

Vuoi saperne di più?

Per saperne di più, consulta queste risorse aggiuntive: