Intervenire contro document.write()

Di recente hai visto un avviso come il seguente nella tua Developers 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à è una delle grandi potenzialità del web, che ci consente di integrarci facilmente con i 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 del cattivo rendimento è l'utilizzo di document.write() all'interno delle pagine, in particolare per gli utilizzi che iniettano 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 l'analizzatore incontra uno script, deve interrompersi ed eseguirlo prima di poter continuare l'analisi dell'HTML. Se lo script inietta dinamicamente un altro script, l'interprete è costretto ad attendere ancora più a lungo per il download della risorsa, il che può comportare uno o più viaggi di andata e ritorno sulla rete e ritardare il tempo necessario per 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 misurazione in Chrome, abbiamo appreso che le pagine con script di terze parti inseriti tramite document.write() impiegano generalmente il doppio a caricarsi rispetto alle altre pagine con connessione 2G.

Abbiamo raccolto i dati di un esperimento sul campo di 28 giorni sull'1% degli utenti stabili di Chrome, limitato agli utenti con connessioni 2G. Abbiamo rilevato che il 7, 6% di tutti i caricamenti di pagine su rete 2G includeva almeno uno script di blocco del parser cross-site inserito tramite document.write() nel documento di primo livello. A seguito del blocco del caricamento di questi script, abbiamo riscontrato i seguenti miglioramenti:

  • 10% in più di caricamenti di pagine che raggiungono First Contentful Paint (una conferma visiva per l'utente che la pagina si sta caricando correttamente), 25% in più di caricamenti di pagine che raggiungono lo stato di analisi completa e 10% in meno di ricaricamenti suggeriscono una diminuzione della frustrazione degli utenti.
  • Riduzione del 21% del tempo medio (oltre un secondo più veloce) fino al primo paint con contenuto
  • Riduzione del 38% del tempo medio necessario per analizzare una pagina, che rappresenta un miglioramento di quasi sei secondi e riduce notevolmente il tempo necessario per visualizzare ciò che è importante per l'utente.

Tenendo conto di questi dati, Chrome, a partire dalla versione 55, interviene per conto di tutti gli utenti quando rileviamo questo pattern noto come dannoso modificando il modo in cui document.write() viene gestito 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.written all'interno degli iframe perché non bloccano il rendering della pagina principale.
  3. Lo script in document.write() blocca il parser. 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 un ritardo della rete e verranno comunque eseguiti.
  6. La richiesta della pagina non è un ricaricamento. Chrome non interviene se l'utente ha attivato una ricarica ed eseguirà la pagina normalmente.

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

Come faccio a risolvere il problema?

La risposta semplice è: non iniettare 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 asincroni, comunicacelo e potremo aggiornare la pagina per aiutare tutti gli utenti.

Se il tuo provider non supporta la possibilità di caricare script in modo asincrono nella tua pagina, ti invitiamo a contattarlo e a comunicarci e comunicargli in che modo sarà interessato.

Se il tuo fornitore ti fornisce uno snippet che include document.write(), potrebbe essere possibile 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 tuo sito è interessato

Esistono una serie di criteri che determinano se la limitazione viene applicata, quindi come fai a sapere se ti riguarda?

Rilevamento della 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.

È fantastico vedere gli avvisi in Chrome DevTools, ma come li rilevi su larga scala? Puoi verificare le intestazioni HTTP inviate al tuo server quando viene eseguito l'intervento.

Controlla le intestazioni HTTP nella risorsa dello script

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

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

Quando viene trovato 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 è di eseguire questo intervento quando rileviamo che i criteri sono soddisfatti. Abbiamo iniziato mostrando solo un avviso nella Console per gli sviluppatori in Chrome 53. (la versione beta è stata rilasciata a luglio 2016. Prevediamo che la versione stabile sarà disponibile per tutti gli utenti a settembre 2016.

Interverremo per bloccare gli script iniettati per gli utenti 2G in via sperimentale a partire da Chrome 54, che dovrebbe essere disponibile in una versione stabile per tutti gli utenti a metà ottobre 2016. Per ulteriori aggiornamenti, consulta la voce dello stato di Chrome.

Nel tempo, prevediamo di intervenire quando la connessione di un utente è lenta (ad es.3G o Wi-Fi lento). Segui questa voce dello stato di Chrome.

Vuoi saperne di più?

Per saperne di più, consulta queste risorse aggiuntive: