Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Async-loaded scripts with DOMContentLoaded or load event handlers not being called?

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!

like image 335
user1203233 Avatar asked Feb 11 '12 01:02

user1203233


People also ask

Does DOMContentLoaded wait for scripts?

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.

What triggers DOMContentLoaded?

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.

How do I know if I am DOMContentLoaded?

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; ... }

What is the difference between DOMContentLoaded and load?

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.


2 Answers

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 ); } 
like image 110
jfriend00 Avatar answered Sep 28 '22 06:09

jfriend00


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.

enter image description here

(Source: Running Your Code at the Right Time from kirupa.com)

like image 38
manus Avatar answered Sep 28 '22 06:09

manus