Otimizar o JavaScript de terceiros

Os scripts de terceiros afetam a performance. Por isso, é importante fazer auditorias regularmente e usar técnicas eficientes para carregá-los. Este codelab mostra como otimizar o carregamento de recursos de terceiros. Ele aborda as seguintes técnicas:

  • Adiando o carregamento do script

  • Recursos não críticos com carregamento lento

  • Pré-conexão às origens necessárias

O aplicativo de exemplo incluído apresenta uma página da Web simples com três recursos provenientes de terceiros:

  • Uma incorporação de vídeo

  • Uma biblioteca de visualização de dados para renderizar um gráfico de linhas

  • Um widget de compartilhamento em mídias sociais

.
Captura de tela da página com recursos de terceiros destacados.
Recursos de terceiros no app de exemplo
.

Você vai começar medindo o desempenho do app e depois vai aplicar cada técnica para melhorar diferentes aspectos dele.

Avaliar o desempenho

Primeiro, abra o app de exemplo na visualização em tela cheia:

  1. Clique em Remixar para editar para tornar o projeto editável.
  2. Para visualizar o site, pressione Ver app. Em seguida, pressione Tela cheia tela cheia

Execute uma auditoria de desempenho do Lighthouse na página para estabelecer o desempenho básico:

  1. Pressione "Control+Shift+J" (ou "Command+Option+J" no Mac) para abrir o DevTools.
  2. Clique na guia Lighthouse.
  3. Clique em Dispositivo móvel.
  4. Marque a caixa de seleção Desempenho. (Você pode desmarcar o restante das caixas de seleção na seção Auditorias.)
  5. Clique em Simular 3G rápido, 4x lentidão da CPU.
  6. Marque a caixa de seleção Limpar armazenamento.
  7. Clique em Executar auditorias.

Ao executar uma auditoria na sua máquina, os resultados exatos podem variar, mas o tempo da First Contentful Paint (FCP) é bastante alto, e o Lighthouse sugere duas oportunidades para investigar: Eliminar os recursos de bloqueio de renderização e Pré-conectar às origens necessárias. Mesmo que todas as métricas estejam em verde, as otimizações ainda produzirão melhorias.

Captura de tela da auditoria do Lighthouse mostrando uma FCP de 2,4 segundos e duas oportunidades: eliminar os recursos de bloqueio de renderização e usar o Preconnect às origens necessárias.

Adiar o JavaScript de terceiros

A auditoria Eliminar os recursos de bloqueio de renderização identificou que é possível poupar tempo ao adiar um script proveniente de d3js.org:

Captura de tela da auditoria "Eliminar os recursos de bloqueio de renderização" com o script d3.v3.min.js destacado.

D3.js é uma biblioteca JavaScript para criar visualizações de dados. O arquivo script.js no app de exemplo usa funções utilitárias do D3 para criar o gráfico de linhas SVG e anexá-lo à página. A ordem das operações é importante aqui: script.js precisa ser executada depois que o documento for analisado e a biblioteca D3 for carregada. Por isso, ela foi incluída logo antes da tag de fechamento </body> no index.html.

No entanto, o script D3 está incluído no <head> da página, que bloqueia a análise do documento restante:

Captura de tela de index.html com a tag de script destacada no cabeçalho.

Dois atributos mágicos podem desbloquear o analisador quando são adicionados à tag de script:

  • O async garante que o download dos scripts seja feito em segundo plano e executados na primeira oportunidade após a conclusão do download.

  • O defer garante que o download dos scripts seja feito em segundo plano e a execução após a conclusão da análise.

Como esse gráfico não é realmente essencial para a página geral e provavelmente estará abaixo da dobra, use defer para garantir que não haja bloqueio do analisador.

Etapa 1: carregar o script de forma assíncrona com o atributo defer

Na linha 17 do index.html, adicione o atributo defer ao elemento <script>:

<script src="https://d3js.org/d3.v3.min.js" defer></script>

Etapa 2: verificar a ordem correta das operações

Agora que o D3 foi adiado, o script.js será executado antes que o D3 esteja pronto, resultando em um erro.

Os scripts com o atributo defer são executados na ordem em que foram especificados. Para garantir que o script.js seja executado depois que o D3 estiver pronto, adicione defer a ele e mova-o para <head> do documento, logo após o elemento <script> do D3. Agora, ele não bloqueia mais o analisador, e o download começa mais cedo.

<script src="https://d3js.org/d3.v3.min.js" defer></script>
<script src="./script.js" defer></script>

Carregamento lento de recursos de terceiros

Todos os recursos abaixo da dobra são bons candidatos para o carregamento lento.

O aplicativo de exemplo tem um vídeo do YouTube incorporado em um iframe. Para conferir quantas solicitações a página faz e quais vêm do iframe incorporado do YouTube:

  1. Para visualizar o site, pressione Ver app. Em seguida, pressione Tela cheia tela cheia
  2. Pressione "Control+Shift+J" (ou "Command+Option+J" no Mac) para abrir o DevTools.
  3. Clique na guia Rede.
  4. Marque a caixa de seleção Desativar cache.
  5. Selecione 3G rápido no menu suspenso Limitação.
  6. Recarregue a página.

Captura de tela do painel &quot;Network&quot; do DevTools.

O painel Rede revela que a página fez um total de 28 solicitações e transferiu quase 1 MB de recursos compactados.

Para identificar as solicitações que o iframe do YouTube fez, procure o ID do vídeo 6lfaiXM6waw na coluna Iniciador. Para agrupar todas as solicitações por domínio:

  • No painel Rede, clique com o botão direito do mouse em um título de coluna.

  • No menu suspenso, selecione a coluna Domínios.

  • Para classificar as solicitações por domínio, clique no título da coluna Domínios.

A nova classificação revela que há solicitações adicionais para os domínios do Google. No total, o iframe do YouTube faz 14 solicitações de scripts, folhas de estilo, imagens e fontes. No entanto, a menos que os usuários rolem a tela para baixo para reproduzir o vídeo, eles não precisam de todos esses recursos.

Ao aguardar o carregamento lento do vídeo até que o usuário role para baixo até essa seção da página, o número de solicitações feitas inicialmente é reduzido. Com essa abordagem, e acelera a carga inicial.

Uma forma de implementar o carregamento lento é usar a Intersection Observer, uma API de navegador que notifica quando um elemento entra ou sai da janela de visualização.

Etapa 1: impedir que o vídeo seja carregado inicialmente

Para fazer o carregamento lento do iframe de vídeo, é necessário primeiro impedir que ele seja carregado da maneira normal. Para isso, substitua o atributo src pelo atributo data-src para especificar o URL do vídeo:

<iframe width="560" height="315" data-src="https://www.youtube.com/embed/lS9D6w1GzGY" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

data-src é um atributo de dados que permite armazenar informações extras em elementos HTML padrão. Um atributo de dados pode receber qualquer nome, desde que comece com "data-".

Um iframe sem um src simplesmente não é carregado.

Etapa 2: usar o Intersection Observer para carregar o vídeo lentamente

Para carregar o vídeo quando um usuário rolar até ele, você precisa saber quando isso acontece. É aí que entra a API Intersection Observer. A API Intersection Observer permite registrar uma função de callback que é executada sempre que um elemento que você quer rastrear entra ou sai da janela de visualização.

Para começar, crie um novo arquivo com o nome lazy-load.js:

  • Clique em Novo arquivo e dê um nome a ele.
  • Clique em Adicionar este arquivo.

Adicione a tag de script ao cabeçalho do documento:

 <script src="/lazy-load.js" defer></script>

Em lazy-load.js, crie um novo IntersectionObserver e transmita a ele uma função de callback a ser executada:

// create a new Intersection Observer
let observer = new IntersectionObserver(callback);

Agora, forneça ao observer um elemento de destino para assistir (o iframe do vídeo, neste caso) transmitindo-o como um argumento no método observe:

// the element that you want to watch
const element = document.querySelector('iframe');

// register the element with the observe method
observer.observe(element);

O callback recebe uma lista de objetos IntersectionObserverEntry e o próprio objeto IntersectionObserver. Cada entrada contém um elemento target e propriedades que descrevem suas dimensões, posição, a hora em que ele entrou na janela de visualização e muito mais. Uma das propriedades de IntersectionObserverEntry é isIntersecting, um valor booleano que é igual a true quando o elemento entra na janela de visualização.

Neste exemplo, target é o iframe. isIntersecting é igual a true quando target entra na janela de visualização. Para conferir como isso funciona, substitua callback pela seguinte função:

let observer = new IntersectionObserver(callback);
let observer = new IntersectionObserver(function(entries, observer) {
    entries.forEach(entry => {
      console.log(entry.target);
      console.log(entry.isIntersecting);
    });
  });
  1. Para visualizar o site, pressione Ver app. Em seguida, pressione Tela cheia tela cheia
  2. Pressione "Control+Shift+J" (ou "Command+Option+J" no Mac) para abrir o DevTools.
  3. Clique na guia Console.

Tente rolar para cima e para baixo. Você verá o valor da mudança de isIntersecting e o elemento de destino registrados no console.

Para carregar o vídeo quando o usuário rolar para a posição, use isIntersecting como uma condição para executar uma função loadElement, que recebe o valor do data-src do elemento iframe e o define como o atributo src do elemento iframe. Essa substituição aciona o carregamento do vídeo. Em seguida, quando o vídeo for carregado, chame o método unobserve no observer para parar de assistir ao elemento de destino:

let observer = new IntersectionObserver(function (entries, observer) {
  entries.forEach(entry => {
    console.log(entry.target);
    console.log(entry.isIntersecting);
  });
});
    if (entry.isIntersecting) {
      // do this when the element enters the viewport
      loadElement(entry.target);
      // stop watching
      observer.unobserve(entry.target);
    }
  });
});

function loadElement(element) {
  const src = element.getAttribute('data-src');
  element.src = src;
}

Etapa 3: reavaliar o desempenho

Para conferir como o tamanho e o número de recursos mudaram, abra o painel Network do DevTools e atualize a página novamente. O painel Rede mostra que a página fez 14 solicitações e apenas 260 KB. Isso é uma melhoria significativa!

Role a página para baixo e observe o painel Network. Quando você chegar ao vídeo, a página deverá acionar solicitações adicionais.

Pré-conectar às origens necessárias

Você adiou o JavaScript não crítico e carregou lentamente as solicitações do YouTube, então agora é hora de otimizar o conteúdo restante de terceiros.

Adicionar o atributo rel=preconnect a um link instrui o navegador a estabelecer uma conexão com um domínio antes de fazer a solicitação desse recurso. Esse atributo é melhor usado em origens que fornecem recursos de que a página precisa.

A auditoria do Lighthouse que você executou na primeira etapa sugerida em Preconectar às origens necessárias pode economizar cerca de 400 ms ao estabelecer conexões iniciais com Staticxx.facebook.com e youtube.com:

Faça a pré-conexão com a auditoria de origens necessária com o domínio &quot;staticxx.facebook.com&quot; destacado.

Como o vídeo do YouTube agora é carregado lentamente, isso deixa apenas o endereço estáticoxx.facebook.com, a fonte do widget de compartilhamento em mídias sociais. Estabelecer uma conexão antecipada com esse domínio é tão simples quanto adicionar uma tag <link> ao <head> do documento:

  <link rel="preconnect" href="https://staticxx.facebook.com">

Reavaliar a performance

Confira o estado da página após a otimização. Siga as etapas da seção Medir o desempenho do codelab para executar outra auditoria do Lighthouse.

Auditoria do Lighthouse mostrando a FCP de 1 segundo e a pontuação de desempenho de 99.