Voglio eseguire un po 'di javascript prima che l'intera pagina sia caricata. È possibile? O il codice inizia a essere eseguito </html>?
Voglio eseguire un po 'di javascript prima che l'intera pagina sia caricata. È possibile? O il codice inizia a essere eseguito </html>?
Risposte:
Non solo puoi , ma devi fare uno sforzo speciale per non farlo se non vuoi. :-)
Quando il browser incontra un scripttag classico durante l'analisi dell'HTML, interrompe l'analisi e passa all'interprete JavaScript, che esegue lo script. Il parser non continua fino al completamento dell'esecuzione dello script (perché lo script potrebbe eseguire document.writechiamate al markup di output che il parser dovrebbe gestire).
Questo è il comportamento predefinito, ma hai alcune opzioni per ritardare l'esecuzione dello script:
Usa i moduli JavaScript. Uno type="module"script viene rinviato fino a quando l'HTML non è stato completamente analizzato e il DOM iniziale creato. Questo non è il motivo principale per utilizzare i moduli, ma è uno dei motivi:
<script type="module" src="./my-code.js"></script>
<!-- Or -->
<script type="module">
// Your code here
</script>
Il codice verrà recuperato (se separato) e analizzato parallelamente all'analisi dell'HTML, ma non verrà eseguito finché non sarà terminata l'analisi dell'HTML. (Se il codice del modulo è in linea anziché nel proprio file, viene anche rinviato fino al completamento dell'analisi HTML.)
Questo non era disponibile quando ho scritto per la prima volta questa risposta nel 2010, ma qui nel 2020 tutti i principali browser moderni supportano i moduli in modo nativo e, se è necessario supportare i browser meno recenti, è possibile utilizzare bundler come Webpack e Rollup.js.
Utilizza l' deferattributo su un tag script classico:
<script defer src="./my-code.js"></script>
Come con il modulo, il codice in my-code.jsverrà recuperato e analizzato in parallelo con l'analisi HTML, ma non verrà eseguito fino a quando non sarà completata l'analisi HTML. Ma , defernon funziona con contenuti script inline, solo con file esterni referenziati via src.
Non penso sia quello che vuoi, ma puoi usare l' asyncattributo per dire al browser di recuperare il codice JavaScript in parallelo con l'analisi HTML, ma poi eseguirlo il prima possibile, anche se l'analisi HTML non è completa . Puoi metterlo su un type="module"tag o usarlo al posto di deferun scripttag classico .
Metti il scripttag alla fine del documento, subito prima del </body>tag di chiusura :
<!doctype html>
<html>
<!-- ... -->
<body>
<!-- The document's HTML goes here -->
<script type="module" src="./my-code.js"></script><!-- Or inline script -->
</body>
</html>
In questo modo, anche se il codice viene eseguito non appena viene rilevato, tutti gli elementi definiti dall'HTML sopra di esso esistono e sono pronti per essere utilizzati.
In passato ciò causava un ulteriore ritardo su alcuni browser perché non iniziavano a recuperare il codice fino a quando non scriptveniva rilevato il tag, ma i browser moderni eseguono la scansione in avanti e iniziano il precaricamento. Tuttavia, questa è decisamente la terza scelta a questo punto, entrambi i moduli e defersono opzioni migliori.
La specifica ha un diagramma utile che mostra un grezzo scripttag, defer, async, type="module", e type="module" asynce la temporizzazione di quando il codice JavaScript viene prelevato ed eseguire:
Ecco un esempio del comportamento predefinito, un scripttag grezzo :
.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>
(Vedi la mia risposta qui per i dettagli su quel NodeListcodice.)
Quando lo esegui, vedi "Paragrafo 1" in verde ma "Paragrafo 2" è nero, perché lo script è stato eseguito in modo sincrono con l'analisi HTML, quindi ha trovato solo il primo paragrafo, non il secondo.
Al contrario, ecco uno 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>
Notate come sono entrambi verdi ora; il codice non è stato eseguito fino al completamento dell'analisi HTML. Ciò sarebbe anche vero con un defer scriptcontenuto esterno (ma non contenuto in linea).
(Non c'era bisogno per il NodeListcontrollo lì perché qualsiasi browser moderno supporto già moduli ha forEachsu NodeList.)
In questo mondo moderno, non c'è valore reale per l' DOMContentLoadedevento della funzionalità "pronta" che PrototypeJS, jQuery, ExtJS, Dojo e molti altri fornivano nel corso della giornata (e forniscono ancora); basta usare moduli o defer. Anche nel passato, non c'erano molti motivi per usarli (e spesso venivano usati in modo errato, bloccando la presentazione della pagina mentre l'intera libreria jQuery veniva caricata perché scriptera nel headdocumento invece che dopo), qualcosa che alcuni sviluppatori a Google ha segnalato all'inizio. Questo era anche uno dei motivi per cui la raccomandazione YUI di inserire gli script alla fine del body, ancora una volta nel corso della giornata.
<body onload="doIt()>".
loadevento si verifica molto tardi nel ciclo di caricamento della pagina, non è quasi mai una buona pratica aspettare di eseguire JavaScript fino ad allora. Ma sì, è un'opzione. Ho revisionato la risposta per il 2020, a proposito.
document.addEventListener('DOMContentLoaded', function(){ //doyour stuff })
Puoi eseguire il codice javascript in qualsiasi momento. AFAIK viene eseguito nel momento in cui il browser raggiunge il tag <script> in cui si trova. Ma non è possibile accedere agli elementi che non sono ancora caricati.
Quindi, se hai bisogno di accedere agli elementi, dovresti aspettare fino a quando il DOM viene caricato (questo non significa che l'intera pagina sia caricata, incluse immagini e cose. È solo la struttura del documento, che viene caricata molto prima, quindi di solito hai vinto notate un ritardo), utilizzando l' DOMContentLoadedevento o le funzioni come $.readyin jQuery.