Scripts: async, defer
Saiba como os atributos async e defer controlam o carregamento de scripts JavaScript, evitando bloqueios no HTML e melhorando o desempenho da página.
O local onde você coloca um <script> e a forma como o carrega têm um efeito direto na velocidade com que sua página fica utilizável. Por padrão, scripts podem paralisar o navegador no meio da renderização; os atributos async e defer permitem que você instrua o navegador a baixar o JavaScript em segundo plano. Este artigo explica como os scripts de bloqueio simples se comportam, o que async e defer mudam, por que scripts de módulo são adiados automaticamente e como escolher a opção certa para cada script.
Como um script simples bloqueia o parsing
Um <script> sem async ou defer é bloqueador de renderização. Quando o parser HTML encontra a tag, ele para de construir a página, busca o script (se tiver um src), executa-o até o fim e só então retoma o parsing do restante do documento:
<p>...content before script...</p>
<script src="big.js"></script> <!-- parsing pauses here until big.js downloads AND runs -->
<p>...content after script (the user can't see this yet)...</p>Duas consequências surgem disso:
- O script não consegue ver elementos DOM que aparecem depois dele, pois ainda não foram processados pelo parser.
- O usuário fica olhando para uma página parcialmente construída enquanto o script é baixado. Em uma rede lenta, este é o clássico problema da "página em branco".
A solução histórica era colocar scripts no final do <body>. async e defer oferecem uma solução mais elegante: mantenha a tag no <head>, mas impeça que ela bloqueie.
Tanto
asyncquantodeferafetam apenas scripts externos — eles exigem o atributosrc. São ignorados em blocos<script>inline.
Entendendo o Atributo async
O que é o Atributo async?
Quando você adiciona o atributo async a uma tag <script>, instrui o navegador a baixar o script em segundo plano sem bloquear o parsing do HTML. Assim que o download termina, o navegador pausa o parsing, executa o script e então continua. Como os tempos de download variam, scripts async são executados assim que ficam prontos — em ordem imprevisível, possivelmente antes de o restante do documento ter sido processado.
Isso torna o async perfeito para scripts independentes que não dependem do DOM nem uns dos outros: analytics, anúncios e outros rastreadores do tipo "disparar e esquecer".
Exemplo de Código: Usando async
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Async Example</title>
</head>
<body>
<h1>Testing Async</h1>
<script async src="https://example.com/async-script.js"></script>
</body>
</html>Benefícios e trade-offs do async
- Sem bloqueio: O parsing do HTML continua enquanto o script é baixado.
- Executa o mais cedo possível: O script é executado no momento em que o download termina — ideal para scripts independentes.
- Sem ordem garantida: Com vários scripts
async, o que baixar primeiro executa primeiro. Nunca useasyncpara scripts que dependem uns dos outros. - Pode executar antes do DOM estar pronto: Pode ser executado antes do parsing terminar, portanto não presuma que elementos posteriores existam.
Aproveitando o Atributo defer
O que é o Atributo defer?
O atributo defer também baixa o script em segundo plano sem bloquear o parsing. A diferença está em quando ele é executado: um script adiado é executado somente após o documento HTML ter sido totalmente processado, e logo antes do evento DOMContentLoaded ser disparado. Scripts com defer também mantêm sua ordem no documento — a primeira tag defer sempre executa antes da segunda, independentemente de qual baixar primeiro.
Isso torna o defer o padrão correto para o código da sua aplicação: todo o DOM tem garantia de existir e os scripts dependentes permanecem em ordem.
Exemplo de Código: Usando defer
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Defer Example</title>
</head>
<body>
<h1>Testing Defer</h1>
<script defer src="https://example.com/defer-script.js"></script>
</body>
</html>Benefícios do Uso do defer
- DOM Pronto: Todo o documento HTML é processado antes da execução do script.
- Ordem Mantida: Os scripts executam na ordem do documento, o que é essencial para scripts que dependem uns dos outros.
Scripts de módulo são adiados por padrão
Um <script type="module"> se comporta como um script adiado automaticamente — você não precisa adicionar defer. Ele é buscado sem bloquear o parsing e executa após o documento ser processado, em ordem. Para fazer um módulo executar assim que estiver pronto (o comportamento do async), adicione async explicitamente:
<!-- Deferred automatically; runs after parsing, in order -->
<script type="module" src="app.js"></script>
<!-- Opt into async: runs as soon as it (and its imports) are ready -->
<script type="module" async src="tracker.js"></script>Se você é novo em módulos, consulte a Introdução a Módulos.
async vs defer em resumo
| Comportamento | async | defer |
|---|---|---|
| Bloqueia o parsing do HTML? | Não | Não |
| Quando executa? | Assim que o download termina | Após o parsing, antes do DOMContentLoaded |
| Ordem de execução | O que baixar primeiro executa primeiro | Ordem do documento, garantida |
| DOM totalmente disponível? | Não garantido | Sim |
| Melhor para | Scripts independentes (analytics, anúncios) | Código da aplicação, scripts dependentes |
Uma regra simples:
- Use
asyncquando o script for independente — não depende de outros scripts nem do DOM. - Use
deferquando o script precisar de todo o DOM ou quando a ordem de execução for importante.
Exemplo Prático: Decisões de Carregamento de Scripts
Considere carregar uma biblioteca utilitária (como o Lodash) mais um arquivo próprio que depende dela. Como a ordem importa aqui, defer é a escolha certa — ambos são baixados em segundo plano, mas executam em sequência após o parsing:
<script defer src="https://cdn.jsdelivr.net/npm/lodash/lodash.min.js"></script>
<script defer src="script.js"></script>Aqui lodash.min.js tem garantia de executar antes de script.js, e ambos aguardam até a página ser processada. Mudar esses scripts para async arriscaria script.js executar primeiro e falhar porque o Lodash ainda não foi carregado.
Para carregar recursos que não são scripts (imagens, estilos) e reagir ao seu sucesso ou falha, veja Carregamento de recursos: onload e onerror.
Conclusão
Usar efetivamente os atributos async e defer em tags de script é fundamental para o desenvolvimento web moderno. Ao entender e aplicar corretamente esses atributos, os desenvolvedores podem garantir carregamentos de página mais rápidos e uma melhor experiência para o usuário. O carregamento assíncrono de scripts trata de otimização de desempenho e da criação de aplicações web eficientes e centradas no usuário.