Quero executar um pouco de javascript antes que toda a página seja carregada. Isso é possível? Ou o código começa a ser executado </html>?
Quero executar um pouco de javascript antes que toda a página seja carregada. Isso é possível? Ou o código começa a ser executado </html>?
Respostas:
Não só você pode , mas você deve fazer um esforço especial para não fazê-lo se não quiser. :-)
Quando o navegador encontra uma scripttag clássica ao analisar o HTML, ele para de analisar e passa para o interpretador JavaScript, que executa o script. O analisador não continua até que a execução do script seja concluída (porque o script pode fazer document.writechamadas para a marcação de saída que o analisador deve manipular).
Esse é o comportamento padrão, mas você tem algumas opções para atrasar a execução do script:
Use módulos JavaScript. Um type="module"script é adiado até que o HTML tenha sido totalmente analisado e o DOM inicial criado. Este não é o principal motivo para usar módulos, mas é um dos motivos:
<script type="module" src="./my-code.js"></script>
<!-- Or -->
<script type="module">
// Your code here
</script>
O código será obtido (se for separado) e analisado em paralelo com a análise HTML, mas não será executado até que a análise HTML seja concluída. (Se o código do módulo estiver embutido em vez de em seu próprio arquivo, ele também será adiado até que a análise de HTML seja concluída.)
Isso não estava disponível quando escrevi esta resposta pela primeira vez em 2010, mas aqui em 2020, todos os principais navegadores modernos suportam módulos nativamente, e se você precisar suportar navegadores mais antigos, pode usar bundlers como Webpack e Rollup.js.
Use o deferatributo em uma tag de script clássico:
<script defer src="./my-code.js"></script>
Tal como acontece com o módulo, o código my-code.jsserá obtido e analisado em paralelo com a análise HTML, mas não será executado até que a análise HTML seja concluída. Mas , defernão funciona com conteúdo de script embutido, apenas com arquivos externos referenciados via src.
Não acho que seja o que você quer, mas você pode usar o asyncatributo para dizer ao navegador para buscar o código JavaScript em paralelo com a análise de HTML, mas depois executá-lo o mais rápido possível, mesmo se a análise de HTML não estiver completa . Você pode colocá-lo em uma type="module"tag ou usá-lo em vez de deferem uma scripttag clássica .
Coloque a scripttag no final do documento, antes da </body>tag de fechamento :
<!doctype html>
<html>
<!-- ... -->
<body>
<!-- The document's HTML goes here -->
<script type="module" src="./my-code.js"></script><!-- Or inline script -->
</body>
</html>
Dessa forma, mesmo que o código seja executado assim que for encontrado, todos os elementos definidos pelo HTML acima dele existem e estão prontos para serem usados.
Antigamente, isso causava um atraso adicional em alguns navegadores porque eles não começavam a buscar o código até que a scripttag fosse encontrada, mas os navegadores modernos fazem a varredura adiante e começam a pré-busca. Ainda assim, esta é a terceira escolha neste ponto, ambos os módulos e defersão opções melhores.
A especificação tem um diagrama útil mostrando uma matéria- scripttag, defer, async, type="module", e type="module" asynce o momento em que o código JavaScript é buscado e corrida:
Aqui está um exemplo do comportamento padrão, uma scripttag bruta :
.found {
color: green;
}
<p>Paragraph 1</p>
<script>
if (typeof NodeList !== "undefined" && !NodeList.prototype.forEach) {
NodeList.prototype.forEach = Array.prototype.forEach;
}
document.querySelectorAll("p").forEach(p => {
p.classList.add("found");
});
</script>
<p>Paragraph 2</p>
(Veja minha resposta aqui para detalhes sobre esse NodeListcódigo.)
Ao executá-lo, você verá "Parágrafo 1" em verde, mas "Parágrafo 2" em preto, porque o script foi executado em sincronia com a análise de HTML e, portanto, encontrou apenas o primeiro parágrafo, não o segundo.
Em contraste, aqui está um type="module"script:
.found {
color: green;
}
<p>Paragraph 1</p>
<script type="module">
document.querySelectorAll("p").forEach(p => {
p.classList.add("found");
});
</script>
<p>Paragraph 2</p>
Observe como eles estão verdes agora; o código não foi executado até que a análise de HTML foi concluída. Isso também seria verdadeiro com um defer scriptconteúdo externo (mas não com conteúdo embutido).
(Não houve necessidade de NodeListverificar porque qualquer navegador moderno com suporte a módulos já está forEachativado NodeList.)
Neste mundo moderno, não há valor real para o DOMContentLoadedevento do recurso "pronto" que PrototypeJS, jQuery, ExtJS, Dojo e muitos outros forneciam (e ainda fornecem); apenas use módulos ou defer. Mesmo no passado, não havia muitos motivos para usá-los (e muitas vezes eram usados incorretamente, segurando a apresentação da página enquanto toda a biblioteca jQuery era carregada porque o scriptestava no em headvez de depois do documento), algo que alguns desenvolvedores em O Google sinalizou no início. Isso também foi parte da razão para a recomendação da YUI de colocar scripts no final do dia body, novamente.
<body onload="doIt()>".
loadevento acontece muito tarde no ciclo de carregamento da página, quase nunca é uma prática recomendada esperar para executar seu JavaScript até então. Mas sim, é uma opção. Eu revisei a resposta para 2020, aliás.
document.addEventListener('DOMContentLoaded', function(){ //doyour stuff })
Você pode executar o código javascript a qualquer momento. O AFAIK é executado no momento em que o navegador atinge a tag <script> onde está. Mas você não pode acessar elementos que ainda não foram carregados.
Portanto, se você precisa de acesso aos elementos, deve esperar até que o DOM seja carregado (isso não significa que toda a página seja carregada, incluindo imagens e outras coisas. É apenas a estrutura do documento, que é carregada muito antes, então você geralmente ganha perceber um atraso), usando o DOMContentLoadedevento ou funções como $.readyem jQuery.