Existem muitas maneiras diferentes de incluir JavaScript em uma página html. Conheço as seguintes opções:
- código embutido ou carregado de URI externo
- incluído na tag <head> ou <body> [ 1 , 2 ]
- sem nenhum
defer
ouasync
atributo (somente scripts externos) - incluído na fonte estática ou adicionado dinamicamente por outros scripts (em diferentes estados de análise, com métodos diferentes)
Sem contar os onEvent
scripts de navegador do disco rígido, javascript: URIs e -atributes [ 3 ], já existem 16 alternativas para executar o JS e tenho certeza de que esqueci alguma coisa.
Não estou tão preocupado com o carregamento rápido (paralelo), estou mais curioso sobre a ordem de execução (que pode depender da ordem de carregamento e da ordem dos documentos ). Existe uma boa referência (entre navegadores) que cubra realmente todos os casos? Por exemplo, http://www.websiteoptimization.com/speed/tweak/defer/ lida apenas com 6 deles e testa principalmente navegadores antigos.
Como eu temo que não exista, aqui está minha pergunta específica: Eu tenho alguns scripts de cabeçalho (externos) para inicialização e carregamento de scripts. Então, eu tenho dois scripts estáticos e embutidos no final do corpo. O primeiro permite que o carregador de scripts inclua dinamicamente outro elemento de script (referenciando js externos) ao corpo. O segundo dos scripts estáticos inline deseja usar js do script externo adicionado. Ele pode confiar na execução do outro (e por que :-)?
fonte
Respostas:
Se você não estiver carregando dinamicamente scripts ou marcando-os como
defer
ouasync
, os scripts serão carregados na ordem encontrada na página. Não importa se é um script externo ou um script embutido - eles são executados na ordem em que são encontrados na página. Os scripts embutidos que vêm depois dos scripts externos são mantidos até que todos os scripts externos que vieram antes deles sejam carregados e executados.Os scripts assíncronos (independentemente de como eles são especificados como assíncronos) são carregados e executados em uma ordem imprevisível. O navegador os carrega em paralelo e é livre para executá-los na ordem que desejar.
Não há ordem previsível entre várias coisas assíncronas. Se alguém precisasse de um pedido previsível, teria que ser codificado registrando-se para receber notificações de carregamento dos scripts assíncronos e sequenciando manualmente as chamadas javascript quando as coisas apropriadas forem carregadas.
Quando uma tag de script é inserida dinamicamente, o comportamento da ordem de execução depende do navegador. Você pode ver como o Firefox se comporta neste artigo de referência . Em poucas palavras, as versões mais recentes do Firefox padronizam uma tag de script adicionada dinamicamente para assíncrona, a menos que a tag de script tenha sido definida de outra forma.
Uma tag de script com
async
pode ser executada assim que for carregada. De fato, o navegador pode pausar o analisador do que quer que esteja fazendo e executar esse script. Portanto, ele realmente pode ser executado a qualquer momento. Se o script foi armazenado em cache, ele pode ser executado quase imediatamente. Se o script demorar um pouco para carregar, ele poderá ser executado após a conclusão do analisador. A única coisa a lembrarasync
é que ele pode ser executado a qualquer momento e esse tempo não é previsível.Uma tag de script
defer
aguarda até que o analisador inteiro seja concluído e, em seguida, executa todos os scripts marcadosdefer
na ordem em que foram encontrados. Isso permite que você marque vários scripts que dependem um do outro comodefer
. Todos serão adiados até após a conclusão do analisador de documentos, mas serão executados na ordem em que foram encontrados, preservando suas dependências. Penso quedefer
os scripts são descartados em uma fila que será processada após a conclusão do analisador. Tecnicamente, o navegador pode estar baixando os scripts em segundo plano a qualquer momento, mas não executará ou bloqueará o analisador até que o analisador termine de analisar a página e de executar e executar scripts embutidos que não estejam marcadosdefer
ouasync
.Aqui está uma citação desse artigo:
A parte relevante da especificação HTML5 (para navegadores compatíveis mais recentes) está aqui . Há muita coisa escrita sobre comportamento assíncrono. Obviamente, essa especificação não se aplica a navegadores mais antigos (ou mal-conformes), cujo comportamento você provavelmente precisaria testar para determinar.
Uma citação da especificação HTML5:
E os scripts do módulo Javascript
type="module"
?Javascript agora tem suporte para carregamento de módulos com sintaxe como esta:
Ou, com o
src
atributo:Todos os scripts com
type="module"
recebem automaticamente odefer
atributo Isso os baixa em paralelo (se não estiver em linha) com outro carregamento da página e os executa em ordem, mas após a conclusão do analisador.Os scripts do módulo também podem receber o
async
atributo que executará os scripts do módulo embutido o mais rápido possível, sem esperar até que o analisador seja concluído e sem esperar para executar oasync
script em qualquer ordem específica em relação a outros scripts.Há um gráfico de linha do tempo bastante útil que mostra a busca e a execução de diferentes combinações de scripts, incluindo scripts de módulo aqui neste artigo: Carregamento de módulo Javascript .
fonte
defer
oferece ao analisador a oportunidade de iniciar o download mais cedo, enquanto adia a execução. Observe que, se você tiver muitos scripts do mesmo host, iniciar o download mais cedo pode realmente atrasar o download de outros usuários do mesmo host (pois eles competem pela largura de banda) em que sua página está aguardando (que não sãodefer
). isso poderia ser uma faca de dois gumes.O navegador executará os scripts na ordem em que os encontrar. Se você chamar um script externo, ele bloqueará a página até que o script seja carregado e executado.
Para testar esse fato:
Os scripts adicionados dinamicamente são executados assim que são anexados ao documento.
Para testar esse fato:
A ordem dos alertas é "anexada" -> "olá!" -> "final"
Se em um script você tentar acessar um elemento que ainda não foi alcançado (exemplo
<script>do something with #blah</script><div id="blah"></div>
:), você receberá um erro.No geral, sim, você pode incluir scripts externos e acessar suas funções e variáveis, mas somente se você sair da
<script>
tag atual e iniciar uma nova.fonte
Um ótimo resumo de @addyosmani
Copiado descaradamente de https://addyosmani.com/blog/script-priorities/
fonte
Depois de testar muitas opções, descobri que a solução simples a seguir está carregando os scripts carregados dinamicamente na ordem em que são adicionados em todos os navegadores modernos
fonte