HTML5 - Async Scripts
O volume de mudanças que a nova especificação do HTML propõe para tag <script>
é pequeno, mas chama atenção por resolver antigos problemas de performance.
Nesse artigo vamos entender quais são esses problemas e dar uma passada geral nas mudanças que o HTML5 propõe para essa tag.
type
Pra começar, lembra do famoso type=text/javascript?
Então, pode esquecer ele. A declaração desse MIME type antes obrigatório no HTML4, se tornou opcional no HTML5, isso é claro, se você utilizar javascript ali dentro.
language
O antigo atributo language, ainda visto em sistemas legados, agora está depreciado devido a nunca ter se tornado um padrão de fato.
O velho problema de performance dos scripts
Quaisquer arquivos javascript quando carregados utilizando a tag <script>
são bloqueantes por natureza.
Enquanto é feito o download e execução do script todo o processo de parser do DOM é bloqueado, impedindo a renderização do resto da página. E olha que isso se aplicada a cada tag de script contida na página.
A especificação do HTTP/1.1 diz que os navegadores não devem proceder com downloads de mais de 2 componentes em paralelo por host.
Uma famosa técnica de otimização de velocidade é servir imagens em múltiplos hosts, assim você consegue mais de dois downloads ocorrendo em paralelo. Entretanto, quando se trata de script o browser não irá iniciar nenhum outro download, enquanto o script é baixado, mesmo que em hosts diferentes.
Navegadores antigos, fazem o carregamento dos scripts um após o outro, veja como funciona no Firefox 3.0.
Alguns browsers já fazem downloads em paralelo, mas o problema de renderização persiste.
async & defer
Os atributos booleanos async e defer vêm para gerenciar exatamente esse tipo de problema. Ou seja, scripts bloqueantes nunca mais.
Para facilitar o entendimento, vou explicar como seria o funcionamento na prática de cada uma dessas linhas:
<script src="exemplo.js"></script>
A página aguarda o script terminar de carregar antes de continuar sua renderização e sua execução é feita imediatamente após. Isso pode aumentar significativamente o tempo de carregamento da página.
<script async src="exemplo.js"></script>
O download do script é feito de forma assíncrona enquanto o processo de renderização da página continua a ser feito. O script é executado depois que o download estiver completo.
<script defer src="exemplo.js"></script>
Assim como o exemplo acima, o download do script é feito de forma assíncrona. Mas sua execução se dá apenas quando todo o processo de renderização estiver concluído.
<script async defer src="exemplo.js"></script>
Nesse caso, o async prevalece e o defer é ignorado. Isso possibilita que os desenvolvedores possam usar async em browsers que o suportam, mas proporciona um fallback com defer para os browsers que não suportam o async.
Compatibilidade
A implementação do atributo async continua lenta em alguns navegadores. A Microsoft, por exemplo, só anunciou o suporte para este atributo na versão 10 que nem foi lançada ainda. Melhor do que o Opera que nem previsão de suporte oferece. Já para o atributo defer a história é outra, sua implementação pela Microsoft é antiga e outros players têm se adaptado há pouco tempo.
Conclusão
Com essa possibilidade de carregar scripts de forma assíncrona, seria a morte dos famosos script loaders, como HeadJS e o LABjs? Essa é uma questão interessante, pois eles chegaram no mercado justamente com o intuito de resolver o problema dos scripts bloqueantes, mas sua permanência ainda deve continuar por um bom tempo. Primeiro por conta do suporte precário de alguns browsers para essas propriedades e segundo porque eles propõe outras funcionalidades bem interessantes. Por exemplo, alguns já combinam todos seus scripts em um só, assim apenas uma requisição HTTP é feita ao servidor, outros possibilitam controles de dependência. O fato é que, acabando ou não com os scripts loaders, esses atributos por mais simples que pareçam vão proporcionar aplicações com muito mais performance para todos nós. HTML5 sem javascript, é como assistir o Tom sem o Jerry, por isso que uma forma otimizada de fazer seu carregamento se mostra tão relevante.