Triggering JavaScript in the intended moment
A quick overview on how to load / run the script at the moment in which they intend to be loaded & executed.
Using “defer”
<script src="script.js" defer></script>
Using defer will trigger after domInteractive (document.readyState = “interactive”) and just before “DOMContentLoaded” Event is triggered. If you need to execute the script after all resources (images, scripts) are loaded use “load” event or target one of the document.readyState states. Read further down for more information about those events / states, as well as async and defer attributes corresponding to script fetching and execution timing.
This Boolean attribute is set to indicate to a browser that the script is meant to be executed after the document has been parsed, but before firing DOMContentLoaded.
Scripts with the defer attribute will prevent the DOMContentLoaded event from firing until the script has loaded and finished evaluating.
Resource: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attributes
* See the images at the bottom for feather explanation.
Event Listeners – Keep in mind that loading of the page has more, than one event:
“DOMContentLoaded”
This event is fired when the initial HTML document has been completely loaded and parsed, without waiting for style sheets, images, and subframes to finish loading. At this stage you could programmatically optimize loading of images and CSS based on user device or bandwidth speed.
Executes after DOM is loaded (before images and CSS):
document.addEventListener("DOMContentLoaded", function(){
//....
});
Note: Synchronous JavaScript pauses parsing of the DOM. If you want the DOM to get parsed as fast as possible after the user requested the page, you could turn your JavaScript asynchronous and optimize loading of style sheets
“load”
A very different event, **load**, should only be used to detect a *fully-loaded page*. It is an incredibly popular mistake to use load where DOMContentLoaded would be much more appropriate, so be cautious.
Executes after everything is loaded and parsed:
document.addEventListener("load", function(){
// ....
});
MDN Resources: https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded https://developer.mozilla.org/en-US/docs/Web/Events/load
MDN list of all events:
https://developer.mozilla.org/en-US/docs/Web/Events
Event Listeners with radyStates – Alternative solution (readystatechange):
You can also track document.readystatechange states to trigger script execution.
// Place in header (do not use async or defer)
document.addEventListener('readystatechange', event => {
switch (document.readyState) {
case "loading":
console.log("document.readyState: ", document.readyState,
`- The document is still loading.`
);
break;
case "interactive":
console.log("document.readyState: ", document.readyState,
`- The document has finished loading DOM. `,
`- "DOMContentLoaded" event`
);
break;
case "complete":
console.log("document.readyState: ", document.readyState,
`- The page DOM with Sub-resources are now fully loaded. `,
`- "load" event`
);
break;
}
});
MDN Resources: https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState
Where to place your script (with & without async/defer)?
This is also very important to know where to place your script and how it positions in HTML as well as parameters like defer and async will affects script fetching, execution and HTML blocking.
* On the image below, the yellow label “Ready” indicates the moment of ending loading HTML DOM. Then it fires: document.readyState = “interactive” >>> defered scripts >>> DOMContentLoaded event (it’s sequential). After that, other Resources (images, css) are being processed after which “load” event is triggered (not shown on the diagrams below).
If your script uses async or defer read this: https://flaviocopes.com/javascript-async-defer/
defer
/async
scripts don’t care about stylesheets at all.
Different from sync scripts, defer
/async
scripts don’t wait for preceding stylesheets, and don’t block subsequent stylesheets/scripts either. They are removed from those “dependency chains” completely. You can’t rely on any proceeding stylesheets to have been parsed.
The differences between defer
/async
:
- as stated above,
defer
scripts have predictable execution time; the DOM has been ready. They are also promised to execute in order. async
scripts have no promise on execution order; eachasync
script would be “queued to execute” as soon as it is fetched; once the render process is idle, they are executed.