Adie Scripts Até Que Sejam Necessários
Carregue JavaScript sob demanda usando IntersectionObserver e gatilhos de interação do usuário

Adie scripts até que sejam necessários
A página mobile mediana envia 251 KB de JavaScript não utilizado, de acordo com o Web Almanac 2025. Isso é JavaScript que o navegador baixa, analisa e compila antes mesmo que um visitante precise dele. Formulários nos quais ninguém clicou. Widgets de chat que ninguém abriu. Integrações de mapas que ficam abaixo da dobra. Tudo isso competindo por largura de banda e tempo de CPU durante a fase mais crítica do carregamento da página.
A maneira mais eficaz de lidar com isso é não carregar scripts até que eles sejam realmente necessários. Isso é diferente de usar o atributo async ou defer em uma tag script. Esses atributos ainda baixam o script durante o carregamento da página; eles apenas alteram quando ele é executado. O carregamento sob demanda não baixa o script de forma alguma até que um gatilho seja acionado.
Última revisão por Arjen Karel em março de 2026
Temos feito isso com imagens há muito tempo. Chama-se lazy loading. Com o lazy loading, uma imagem abaixo da dobra é carregada logo antes de rolar para a visualização. O navegador pode gastar seus recursos baixando, analisando e pintando coisas que são realmente necessárias. O mesmo princípio se aplica ao JavaScript, e isso corrigirá o aviso do Lighthouse "reduce unused JavaScript" e melhorará métricas de responsividade como Interaction to Next Paint (INP).
Infelizmente, não é tão simples quanto adicionar loading="lazy" a uma imagem, mas com uma pequena função auxiliar e um gatilho, podemos fazer funcionar.
O auxiliar de injeção de script
Para adicionar scripts à página após o carregamento da página, precisamos de uma pequena função que cria um elemento script e o anexa ao cabeçalho do documento.
function injectScript(scriptUrl, callback) {
const script = document.createElement('script');
script.src = scriptUrl;
if (typeof callback === 'function') {
script.onload = callback;
}
document.head.appendChild(script);
}
O parâmetro scriptUrl é o URL do script a ser carregado. A função callback opcional é executada após o término do carregamento do script. Isso é importante para scripts que precisam de inicialização, como chamar initMap() após carregar a API do Google Maps.
Acionando o carregamento sob demanda
Com o auxiliar de injeção em vigor, precisamos de um gatilho. Existem dois métodos confiáveis: carregar quando um elemento rola para a visualização, e carregar quando o usuário interage com um elemento.
IntersectionObserver: carregar quando visível
O IntersectionObserver é acionado quando um elemento entra na viewport. Este é o gatilho certo para scripts vinculados a uma seção específica da página: um contêiner de mapa, uma seção de comentários ou um widget incorporado abaixo da dobra.
function injectScriptOnIntersection(scriptUrl, elementSelector, callback) {
const element = document.querySelector(elementSelector);
const observer = new IntersectionObserver((entries, obs) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
injectScript(scriptUrl, callback);
obs.unobserve(entry.target);
}
});
});
observer.observe(element);
}
A função recebe o URL do script, um seletor CSS para o elemento que deve acionar o carregamento e um callback opcional para inicialização. Quando o elemento rola para a visualização, o script é injetado e o observador se desconecta.
// Carregue a API do Google Maps quando o contêiner do mapa rolar para a visualização
injectScriptOnIntersection(
'https://maps.googleapis.com/maps/api/js?key=YOUR_KEY',
'#map-container',
() => initMap()
);
O IntersectionObserver é suportado em todos os navegadores modernos (95,76% de cobertura global de acordo com o Can I Use). Nenhum polyfill é necessário.
Na interação: carregar quando o usuário engaja
O método mais eficaz é carregar um script apenas quando o visitante realmente interage com o elemento que precisa dele. Um widget de chat não precisa carregar até que alguém clique no botão de chat. Uma biblioteca de validação de formulário não precisa carregar até que o usuário foque em um campo do formulário.
function injectScriptOnInteraction(scriptUrl, elementSelector, eventTypes, callback) {
const element = document.querySelector(elementSelector);
const handler = () => {
eventTypes.forEach(type => element.removeEventListener(type, handler));
injectScript(scriptUrl, callback);
};
eventTypes.forEach(type => {
element.addEventListener(type, handler);
});
}
Esta função escuta os eventos especificados no elemento alvo. No primeiro evento, ela remove todos os ouvintes (listeners) e injeta o script. A vantagem: se o visitante nunca interagir com o elemento, o script nunca será carregado.
// Carregue o script do widget de chat quando o botão de chat for clicado ou ao passar o mouse
injectScriptOnInteraction(
'chat-widget.js',
'#chat-button',
['click', 'mouseover', 'touchstart'],
() => initChat()
);
Impacto no mundo real
Esse padrão funciona para qualquer script que não seja necessário durante o carregamento inicial da página. Alguns casos de uso comuns:
- Widgets de chat: Um widget de chat típico carrega de 200 a 400 KB de JavaScript. Quando o Postmark adiou seu widget Intercom para carregar no clique em vez de antecipadamente, seu Time to Interactive caiu de 7,7 segundos para 3,7 segundos.
- Incorporações de vídeo: Uma incorporação do YouTube carrega mais de 1 MB de dados. Mostre uma miniatura com um botão de reprodução e carregue a incorporação no clique.
- Integrações de mapas: O Google Maps carrega centenas de kilobytes de JavaScript. Use IntersectionObserver para carregá-lo quando o contêiner do mapa rolar para a visualização.
- Analytics e rastreamento: Scripts de analytics podem esperar até depois da primeira interação do usuário. Ninguém nunca ficou desapontado que sua ferramenta de mapa de calor começou a gravar 3 segundos após o carregamento da página.
- Bibliotecas de formulários: Bibliotecas de validação, seletores de data e editores de rich text podem carregar quando o usuário foca no formulário.
Quando não adiar
Nem todo script deve ser adiado. Se um script é responsável por renderizar conteúdo acima da dobra, adiá-lo tornará o seu Largest Contentful Paint pior, não melhor. Scripts que inicializam a navegação do seu cabeçalho, renderizam sua seção hero ou configuram variantes críticas de testes A/B precisam ser executados cedo.
A regra é simples: se o visitante for ver ou interagir com o que o script produz dentro da primeira viewport, carregue-o normalmente. Se o script alimenta algo abaixo da dobra ou por trás de uma ação do usuário, adie-o usando um dos padrões acima.
Dica: Para uma visão geral completa de todas as estratégias de carregamento de JavaScript, consulte 16 métodos para adiar ou agendar JavaScript.
Medindo a melhoria
O Web Almanac 2025 relata um Total Blocking Time mediano em dispositivos móveis de 1.916 ms, um aumento de 58% em relação a 2024. Grande parte desse bloqueio vem de JavaScript que não precisava ser executado durante o carregamento da página. Ao adiar scripts não críticos, você os remove inteiramente do caminho crítico.
Após implementar o carregamento sob demanda, verifique a melhoria com Real User Monitoring. Verifique suas pontuações de INP e Total Blocking Time em dados de campo, não apenas no Lighthouse. Os testes de laboratório rodam em máquinas rápidas com caches vazios. Seus visitantes estão em redes móveis com 15 abas de navegador abertas. É aí que a diferença aparece.
Performance degrades unless you guard it.
I do not just fix the metrics. I set up the monitoring, the budgets, and the processes so your team keeps them green after I leave.
Start the Engagement
