On my website I use javascript modules, which according to MDN are deferred by default. I have some additional javascript which can only safely execute once these modules have loaded and executed. MDN indicates here that deferred script execution is guaranteed to have occurred by the time the DOMContentLoaded event has fired. Further, it is suggested here that you can also account for the case where this event has already fired like so:
function doSomething() {
console.info('DOM loaded');
}
if (document.readyState === 'loading') { // Loading hasn't finished yet
document.addEventListener('DOMContentLoaded', doSomething);
} else { // `DOMContentLoaded` has already fired
doSomething();
}
The block above seems to be what I'm looking for. But documentation elsewhere on MDN leaves me unsure as to whether this is really correct. For instance, why does the readystate check above look for loading rather than loading OR interactive? The documentation on readystate says that loading is followed by interactive, and that in the interactive state " sub-resources such as scripts, images, stylesheets and frames are still loading."
So it seems to me that there is an inconsistency here. Either the suggested readystate check is not sufficient to guarantee that DOMContentLoaded has fired, or DOMContentLoaded is not sufficient to guarantee that deferred scripts have completed.
When
readyStateis at leastinteractive, that means that the document has been fully parsed, and that all the elements in the source HTML now exist in the DOM.Usually, people implementing this solution are doing so because they're trying to attach listeners to elements, and need to wait for all elements to exist in the DOM - and so all they need to do is check
document.readyState === 'loading'.If you also want to wait for
<script type="module">scripts to run, that's a different problem, with a different solution.The best way by far would be to have a single entry point for your app's in a module, so that you don't have to worry about loading order at all - it'll just work.
If you really have to determine when all module scripts have run from a non-module script (which I wouldn't recommend), you'd have to iterate over them and listen to their
loadevents.But that's quite convoluted and probably isn't a good approach.
If you listen to the
loadevent for the window instead, you'll also be waiting for all other resources to load as well (images and stylesheets and such) which isn't desirable.