Intervenire contro document.write()

Di recente hai visto un avviso come il seguente nella tua Console per gli sviluppatori in Chrome e ti sei chiesto di che cosa si tratta?

(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 servizi creati da terze parti per creare nuovi fantastici prodotti. Uno degli svantaggi della componibilità è che implica una responsabilità condivisa sull'esperienza utente. Se l'integrazione non è ottimale, l'esperienza utente ne risentirà.

Una causa nota dello scarso rendimento è l'utilizzo di document.write() all'interno delle pagine, in particolare gli utilizzi che inseriscono script. Anche se sembra innocuo, 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 l'albero DOM analizzando il markup HTML. Ogni volta che il parser rileva uno script, deve arrestarlo ed eseguirlo prima di poter continuare ad analizzare l'HTML. Se lo script inserisce dinamicamente un altro script, l'analizzatore sintattico deve attendere ancora più a lungo per il download della risorsa, il che può comportare uno o più round trip di rete e ritardare il primo rendering della pagina

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

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

  • 10% in più di caricamenti pagina raggiungendo la prima visualizzazione con contenuti (una conferma visiva per l'utente che la pagina viene caricata correttamente), un 25% in più di caricamenti pagina raggiungendo lo stato di analisi completa e il 10% in meno di ricariche, il che suggerisce una diminuzione della frustrazione per gli utenti.
  • 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, con un miglioramento di quasi sei secondi e una riduzione drastica del tempo necessario per mostrare ciò che conta per l'utente.

Tenendo a mente questi dati, Chrome, a partire dalla versione 55, interviene per conto di tutti gli utenti quando rileviamo questo pattern di errore noto cambiando la modalità di gestione di document.write() in Chrome (vedi lo stato di Chrome). In particolare, Chrome non eseguirà gli elementi <script> inseriti tramite document.write() se sono soddisfatte tutte le seguenti condizioni:

  1. La connessione dell'utente è lenta, in particolare quando è attiva la connessione 2G. In futuro, la modifica potrebbe essere estesa ad altri utenti con connessioni lente, ad esempio una connessione 3G lenta o una connessione Wi-Fi lenta.
  2. document.write() si trova in un documento di primo livello. L'intervento non si applica agli script document.writer all'interno degli iframe in quanto non bloccano il rendering della pagina principale.
  3. Lo script in document.write() sta bloccando il parser. Gli script con gli attributi "async" o "defer" verranno comunque 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 è già presente nella cache HTTP del browser. Gli script nella cache non subiranno un ritardo di rete e saranno comunque eseguiti.
  6. La richiesta per la pagina non è un ricaricamento. Chrome non interverrà se l'utente ha attivato un ricaricamento ed esegue 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 degli script di terze parti senza bloccare la visualizzazione del resto dei contenuti sulla pagina.

Come faccio a risolvere questo 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 è nell'elenco e supporta il caricamento asincrono degli script, comunicacelo e potremo aggiornare la pagina per aiutare tutti gli utenti.

Se il tuo provider non supporta la possibilità di caricare gli script in modo asincrono nella pagina, ti invitiamo a contattarlo e a farci sapere 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 oppure aggiungere gli elementi script con API DOM come document.appendChild() o parentNode.insertBefore().

Come rilevare quando il sito è interessato

Sono molti i criteri che determinano se la limitazione viene applicata. Come fai a sapere se la limitazione viene applicata?

Rileva quando un utente è connesso a una rete 2G

Per comprendere il potenziale impatto di questo cambiamento, devi prima capire 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 tuoi 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 genera 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 al seguente:

Avviso di scrittura di documenti.

Vedere gli avvisi in Chrome DevTools è fantastico, ma come si fa a rilevare questi su larga scala? Puoi verificare la presenza di intestazioni HTTP inviate al tuo server quando viene eseguito l'intervento.

Controlla le intestazioni HTTP nella risorsa di 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 di intervento verrà inviata come parte della richiesta GET per lo script (in modo asincrono in caso di un intervento effettivo).

Che cosa ci riserva il futuro?

Il piano iniziale prevede di eseguire questo intervento quando rileviamo che vengono soddisfatti i criteri. Abbiamo iniziato mostrando solo un avviso nella Developer Console in Chrome 53. (versione beta risalente a luglio 2016. Prevediamo che il servizio stabile sarà disponibile per tutti gli utenti a settembre 2016).

Interverremo temporaneamente per bloccare gli script inseriti per gli utenti 2G a partire da Chrome 54, che si prevede sia in una release 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, una connessione 3G o Wi-Fi lenta). Segui questa voce sullo stato di Chrome.

Ti piacerebbe saperne di più?

Per saperne di più, consulta queste risorse aggiuntive: