Order of loading scripts and modules
There are the following script include mechanisms used in this page:
- A script block 'top-script:' in the <head> in this page
- A script block 'end-script:' an the end of the <body> in this page
- A script block of type 'module'
- A script in an external file included using a untyped <script> tag
- A script in an external typescript module file
- A script in an external module imported using the import statement
This creates the following output:
script: start script: end getPrimes: start getPrimes: end module: start WaitDocument: interactive DOMContentLoaded event module: ready load event module: done
Blocking scripts
As expected the script in the header is executed first. When counting the script elements in the document only 2 of them are available so the document is not available completely.
The script at the end of the body is executed next but again the number of script tags and the document is still incomplete.
When using the blocking script from 06 Top Level Scripting you can see that both script blocks are blocking further loading and activation.
Using 'async' or 'defer' attributes on these script tags has no effect as defined by the standard.
You can activate and try this by adding a ?block parameter to the url.
You will see the counting the console output and that the loading other script blocks and modules are blocked.
Module scripts
<script type="module">
import { getPrimes } from './00primes.js'
...
Module script are loaded in an async mode. What can be observed that the imported modules using the ES6 import statement are even executed before the start of the importing script.
When there are async functions in this script (as await is allowed) it may happen that the DOMContentLoaded and load events are dispatched even before the module script terminates. You can activate and try this by adding a ?wait parameter to the url.
You will see in the console output that the `module: count` and `module: done` will appear after the `load` event.
Use Modules after `load` is done
Sometimes it is important to be sure that at least the main document has loaded completely.
This can be done using the trick from 06 Top Level Scripting
to execute code by a trigger of the 06 Top Level Scripting
using window.addEventListener("DOMContentLoaded", async f());
but wait...
Here is a Promise based function that waits for the document to be loaded completely.
// Promise to wait for document loaded completely.
function WaitDocument() {
console.info('WaitDocument:', document.readyState);
return new Promise(function (resolve, _reject) {
if (document.readyState === 'complete') {
resolve();
} else {
window.addEventListener('load', _e => {
console.info('WaitDocument:', document.readyState);
resolve();
});
}
});
}
This can be used in module scripts by using a single statement: await WaitDocument();
You can activate and try this by adding a ?ready parameter to the url.
You will see in the console output that the `module: ready` and following infos will appear after the `load` event.
Summary
Using top level Scripts are too blocky so converting them into javascript modules is a good option.
See Also
- 06 Top Level Scripting
- https://moderncss.dev/the-3-css-methods-for-adding-element-borders/
- https://hacks.mozilla.org/2015/08/es6-in-depth-modules/