I've got a script with a DOMContentLoaded
event handler—
document.addEventListener('DOMContentLoaded', function() { console.log('Hi'); });
Which I'm loading asynchronously—
<script async src=script.js></script>
However, the event handler is never called. If I load it synchronously—
<script src=script.js></script>
It works fine.
(Even if I change the DOMContentLoaded
event to a load
event, it's never called.)
What gives? The event handler should be registered irrespective of how the script is loaded by the browser, no?
Edit: It doesn't work on Chrome 18.0.1025.11 beta but, with DOMContentLoaded
, it does on Firefox 11 beta (but with load
it doesn't). Go figure.
OH GREAT LORDS OF JAVASCRIPT AND THE DOM, PRAY SHOW THE ERROR OF MY WAYS!
DOMContentLoaded and styles External style sheets don't affect DOM, so DOMContentLoaded does not wait for them. The reason for this is that the script may want to get coordinates and other style-dependent properties of elements, like in the example above.
The DOMContentLoaded event fires when the initial HTML document has been completely loaded and parsed, without waiting for stylesheets, images, and subframes to finish loading.
If you want to know "exactly" if DOMContentLoaded was fired, you could use a boolean flag like this: var loaded=false; document. addEventListener('DOMContentLoaded',function(){ loaded=true; ... }
The load event is fired when the whole page has loaded, including all dependent resources such as stylesheets and images. This is in contrast to DOMContentLoaded , which is fired as soon as the page DOM has been loaded, without waiting for resources to finish loading. This event is not cancelable and does not bubble.
By loading the script asynchronously, you are telling the browser that it can load that script independently of the other parts of the page. That means that the page may finish loading and may fire DOMContentLoaded
BEFORE your script is loaded and before it registers for the event. If that happens, you will miss the event (it's already happened when you register for it).
In all modern browsers, you can test the document to see if it's already loaded (MDN doc), you can check:
if (document.readyState !== "loading")
to see if the document is already loaded. If it is, just do your business. If it's not, then install your event listener.
In fact, as a reference source and implementation idea, jQuery does this very same thing with it's .ready()
method and it looks widely supported. jQuery has this code when .ready()
is called that first checks to see if the document is already loaded. If so, it calls the ready function immediately rather than binding the event listener:
// Catch cases where $(document).ready() is called after the // browser event has already occurred. if ( document.readyState === "complete" ) { // Handle it asynchronously to allow scripts the opportunity to delay ready return setTimeout( jQuery.ready, 1 ); }
This is not the final answer but made me understand why is not correct using async with a script that need to modify DOM, so must wait to DOMContentLoaded event. Hope could be beneficial.
(Source: Running Your Code at the Right Time from kirupa.com)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With