Como intervir em document.write()

Você viu recentemente um aviso como o seguinte no console do desenvolvedor do Chrome e se perguntou o que era?

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

A composição é um dos grandes poderes da Web, permitindo-nos faça a integração com serviços de terceiros para desenvolver novos produtos incríveis. Um das desvantagens da composição é que ela implica uma responsabilidade compartilhada sobre a experiência do usuário. Se a integração não for ideal, a experiência do usuário serão prejudicadas.

Uma causa conhecida de desempenho insatisfatório é o uso de document.write() dentro das páginas, especificamente os usos que injetam scripts. Por mais inofensiva que pareça, ela pode causar problemas reais para os usuários.

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

Antes que o navegador possa renderizar uma página, ele precisa criar a árvore do DOM analisando a marcação HTML. Sempre que o analisador encontra um script, precisa interrompê-lo e executá-lo antes de continuar ao analisar o HTML. Se o script injetar dinamicamente outro script, o analisador será forçado a aguardar o download do recurso por mais tempo, o que pode resultar em uma ou mais idas e voltas na rede atrasar a primeira renderização da página

Para usuários com conexões lentas, como 2G, scripts externos dinamicamente injetada pelo document.write() pode atrasar a exibição do conteúdo da página principal para vários segundos, ou fazer com que as páginas não carreguem ou demorem tanto que o o usuário desiste. Com base na instrumentação do Chrome, aprendemos que as páginas com scripts de terceiros inseridos por document.write() estão o carregamento geralmente é duas vezes mais lento do que outras páginas em 2G.

Coletamos dados de um teste de 28 dias em 1% do Chrome usuários estáveis, restritos a usuários em conexões 2G. Notamos que 7,6% de todos os carregamentos de página em 2G incluía pelo menos um script de bloqueio de analisador entre sites inserido pelo document.write() no documento de nível superior. Como resultado do bloqueio o carregamento desses scripts, notamos as seguintes melhorias nesses carregamentos:

  • 10% mais carregamentos de página alcançando First Contentful Paint (uma confirmação visual para o usuário de que a página está carregando efetivamente), 25% mais carregamentos de página alcançando o estado totalmente analisado e 10% menos atualizações sugerindo uma diminuição da frustração do usuário.
  • 21% de redução do tempo médio (mais de um segundo mais rápido) até que o First Contentful Paint
  • 38% de redução ao tempo médio necessário para analisar uma página, representando uma de quase seis segundos, reduzindo drasticamente o tempo que ele leva para mostrar o que é importante para o usuário.

Com esses dados em mente, o Chrome, a partir da versão 55, intervir em nome de todos quando detectamos esse padrão inadequado, mudando a forma como document.write() é manualmente no Chrome (consulte Status do Chrome). Especificamente, o Chrome não executará os elementos <script> injetados via document.write() quando todas as condições a seguir são atendidas:

  1. O usuário está com uma conexão lenta, especificamente quando está em 2G. (Em no futuro, a mudança pode ser estendida para outros usuários em conexões lentas, como conexão 3G lenta ou Wi-Fi lento).
  2. O document.write() está em um documento de nível superior. A intervenção não são aplicadas a scripts document.scritos em iframes, porque não bloqueiam renderização da página principal.
  3. O script no document.write() bloqueia o analisador. Scripts com o campo "async" ou "defer" atributos ainda serão executados.
  4. O script não está hospedado no mesmo site. Em outras palavras, o Chrome não intervir em scripts com um eTLD+1 correspondente (por exemplo, um script hospedado em js.example.org inserida em www.example.org).
  5. O script ainda não está no cache de HTTP do navegador. Scripts no cache não vai causar atrasos na rede e ainda será executado.
  6. A solicitação da página não é uma atualização. O Chrome não intervém se a o usuário acionou uma atualização e executará a página normalmente.

Às vezes, os snippets de terceiros usam document.write() para carregar scripts. Felizmente, a maioria dos terceiros fornece alternativas de carregamento assíncrono, que que scripts de terceiros sejam carregados sem bloquear a exibição do restante o conteúdo da página.

Como resolvo esse problema?

A resposta simples é não injetar scripts usando document.write(). Qa manter um conjunto de serviços conhecidos para suporte a carregador assíncrono. que recomendamos que você continue verificando.

Se o provedor não estiver na lista e oferecer suporte ao carregamento de script assíncrono Informe-nos para que possamos atualizar a página e ajudar todos os usuários.

Se o provedor não oferecer suporte à capacidade de carregar scripts de forma assíncrona na sua página, então recomendamos que você entre em contato com eles e avise nossa equipe e eles como elas serão afetadas.

Se o provedor fornecer um snippet que inclua o document.write(), ele talvez seja possível adicionar um atributo async ao elemento de script ou para você adicionar os elementos de script com a API DOM, como document.appendChild(). ou parentNode.insertBefore().

Como detectar quando seu site é afetado

Há um grande número de critérios que determinam se a restrição é aplicada, então, como saber se você foi afetado?

Como detectar quando um usuário está usando 2G

Para entender o possível impacto dessa mudança, primeiro você precisa entender quantos usuários usarão 2G. Você pode detectar o tipo de rede atual do usuário e velocidade usando a API Network Information, que está disponível no Chrome e envie um aviso para suas métricas analíticas ou de usuários reais (RUM).

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

Detectar avisos no Chrome DevTools

Desde o Chrome 53, o DevTools emite avisos para document.write() problemáticos declarações. Especificamente, se uma solicitação document.write() atender aos critérios 2 a 5 O Chrome ignora os critérios de conexão ao enviar esse aviso. é semelhante a:

Aviso de gravação de documento.

Ver avisos no Chrome DevTools é ótimo, mas como detectar isso em escala? Você pode verificar cabeçalhos HTTP que são enviados ao seu servidor quando o antes da intervenção.

Verifique seus cabeçalhos HTTP no recurso de script

Quando um script inserido por document.write for bloqueado, o Chrome enviará o seguinte cabeçalho ao recurso solicitado:

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

Quando um script inserido via document.write é encontrado e pode ser bloqueado diferentes circunstâncias, o Chrome poderá enviar:

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

O cabeçalho da intervenção será enviado como parte da solicitação GET para o script (de forma assíncrona, no caso de uma intervenção real).

O que o futuro reserva?

O plano inicial é executar essa intervenção quando detectarmos os critérios sendo atendidos. Começamos mostrando apenas um aviso no Play Console no Chrome 53. A versão Beta foi em julho de 2016. A expectativa é que o Stable esteja disponível para todos os usuários em Setembro de 2016.)

Interviremos para bloquear provisoriamente scripts injetados para usuários de 2G a partir de Chrome 54, que deve ter uma versão estável para todos os usuários no meados de outubro de 2016. Consulte o Entrada de status do Chrome para mais atualizações.

Com o tempo, tentamos intervir quando algum usuário tem uma conexão lenta (por exemplo, conexão 3G ou Wi-Fi lento). Siga esta entrada de status do Chrome.

Quer saber mais?

Para saber mais, consulte estes recursos extras: