Se você não estiver carregando dinamicamente scripts ou marcando-os como defer
ou async
, 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 lembrar async
é 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 marcados defer
na ordem em que foram encontrados. Isso permite que você marque vários scripts que dependem um do outro como defer
. 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 que defer
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 marcados defer
ou async
.
Aqui está uma citação desse artigo:
scripts inseridos em script são executados de forma assíncrona no IE e WebKit, mas de forma síncrona no Opera e no Firefox anterior à 4.0.
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:
Em seguida, a primeira das seguintes opções que descreve a situação deve ser seguida:
Se o elemento tiver um atributo src e o elemento tiver um atributo defer, e o elemento tiver sido marcado como "inserido pelo analisador", e o elemento não tiver um atributo assíncrono.
O elemento deve ser adicionado ao final da lista de scripts que serão executados quando o documento terminar de analisar associado ao documento do analisador que criou o elemento.
A tarefa que a origem da tarefa de rede coloca na fila de tarefas após a conclusão do algoritmo de busca deve definir o sinalizador "pronto para ser executado pelo analisador" do elemento. O analisador manipulará a execução do script.
Se o elemento tiver um atributo src e o elemento tiver sido marcado como "inserido pelo analisador" e o elemento não tiver um atributo assíncrono
O elemento é o script de bloqueio de análise pendente do Documento do analisador que criou o elemento. (Só pode haver um desses scripts por documento de cada vez.)
A tarefa que a origem da tarefa de rede coloca na fila de tarefas após a conclusão do algoritmo de busca deve definir o sinalizador "pronto para ser executado pelo analisador" do elemento. O analisador manipulará a execução do script.
Se o elemento não tiver um atributo src e o elemento tiver sido sinalizado como "inserido pelo analisador", e o Documento do analisador HTML ou XML que criou o elemento de script terá uma folha de estilos que está bloqueando os scripts. O elemento é o script de bloqueio de análise pendente do Documento do analisador que criou o elemento. (Só pode haver um desses scripts por documento de cada vez.)
Defina o sinalizador "pronto para ser executado pelo analisador" do elemento. O analisador manipulará a execução do script.
Se o elemento tiver um atributo src, não possuir um atributo assíncrono e não tiver o sinalizador "force-async" definido, o elemento deverá ser adicionado ao final da lista de scripts que serão executados na ordem o mais breve possível associada com o documento do elemento de script no momento em que o algoritmo de preparação de um script foi iniciado.
A tarefa que a origem da tarefa de rede coloca na fila de tarefas após a conclusão do algoritmo de busca deve executar as seguintes etapas:
Se agora o elemento não for o primeiro na lista de scripts que serão executados na ordem o mais rápido possível à qual foi adicionado acima, marque o elemento como pronto, mas aborte essas etapas sem executar o script ainda.
Execução: Execute o bloco de scripts correspondente ao primeiro elemento de script nesta lista de scripts que serão executados na ordem o mais rápido possível.
Remova o primeiro elemento desta lista de scripts que serão executados em ordem o mais rápido possível.
Se essa lista de scripts que serão executados em ordem o mais rápido possível ainda não estiver vazia e a primeira entrada já tiver sido marcada como pronta, volte para a etapa rotulada execução.
Se o elemento tiver um atributo src O elemento deve ser incluído no conjunto de scripts que serão executados o mais rápido possível do Documento do elemento de script no momento em que o algoritmo de preparação de um script foi iniciado.
A tarefa que a origem da tarefa de rede coloca na fila de tarefas após a conclusão do algoritmo de busca deve executar o bloco de scripts e remover o elemento do conjunto de scripts que serão executados o mais rápido possível.
Caso contrário, o agente do usuário deve executar imediatamente o bloco de scripts, mesmo se outros scripts já estiverem em execução.
E os scripts do módulo Javascript type="module"
?
Javascript agora tem suporte para carregamento de módulos com sintaxe como esta:
<script type="module">
import {addTextToBody} from './utils.mjs';
addTextToBody('Modules are pretty cool.');
</script>
Ou, com o src
atributo:
<script type="module" src="http://somedomain.com/somescript.mjs">
</script>
Todos os scripts com type="module"
recebem automaticamente o defer
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 o async
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 .