When exactly the $(document).ready callback is executed?

Suppose that we attach a .click() handler to an anchor (<a>) tag in the $(document).ready callback. This handler will cancel the default action (following the href) and show an alert.

What I would like to know is when exactly the callback will execute and is it possible for the user to click on the anchor (the document has been shown in the browser) but the event hasn't been attached yet.

Here are different HTML pages that contain an anchor but the order of inclusion of the scripts is different. What's the difference (if any) between them? Will different browsers behave differently?

Page1:

<html>
<head>
    <title>Test 1</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js"></script>
    <script type="text/javascript">
    $(function() {
        $('a').click(function() {
            alert('overriding the default action');
            return false;
        });
    });
    </script>
</head>
<body>
    <a href="http://www.google.com">Test</a>
</body>
</html>

Page2:

<html>
<head>
    <title>Test 1</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js"></script>
</head>
<body>
    <a href="http://www.google.com">Test</a>
    <script type="text/javascript">
    $(function() {
        $('a').click(function() {
            alert('overriding the default action');
            return false;
        });
    });
    </script>
</body>
</html>

Page3:

<html>
<head>
    <title>Test 1</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
    <a href="http://www.google.com">Test</a>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js"></script>
    <script type="text/javascript">
    $(function() {
        $('a').click(function() {
            alert('overriding the default action');
            return false;
        });
    });
    </script>
</body>
</html>

So is it possible that a user gets redirected to the href by clicking on the anchor and never sees the alert (ignoring the case of javascript disabled of course)? Could this happen in any of the examples I provided?

All that I need is to make sure that the click event handler has been attached to the anchor before the user has any possibility to click on this anchor. I know that I can provide an empty href and then progressively enhance it in javascript but this is a more general question.

What will happen in case that the HTML is quickly generated by the web server but the jquery library takes time to be fetched from a distant server? Will this influence my scenario? What's the order of inclusion of the scripts compared to loading the DOM? Could they be done in parallel?


Solution 1:

Example 3 will have the highest chance of the user being able to click on the link without the handler having attached itself yet. Since you are loading the jQuery library after the link is rendered, if Google's servers are a little slow (or the DNS lookup takes a second or so), or the users computer is slow to process jQuery, the link will not have its click handler attached when the user tries to click it.

Another situation where this might happen is if you have a very large or slow loading page and this link is at the top. Then the DOM may not be fully ready when parts of it are visible. If you are running into a problem like this, the safest thing to do is:

  1. Load jQuery in the head (example 1 or 2)
  2. Attach the click event immediately after the <a> element, but not in a DOMReady callback. This way it will be called immediately and will not wait for the rest of the document.

Once an element is rendered, it can be grabbed from the DOM, and subsequently jQuery can access it:

<a href="http://www.google.com">Test</a>
<script type="text/javascript>
    // No (document).ready is needed. The element is availible
    $('a').click(function() {
        alert('overriding the default action');
        return false;
    });
</script>

Additionally, building on user384915's comment, if the action is fully dependent on JavaScript, then don't even render it as part of the HTML, add it after jQuery is ready:

<script type="text/javascript">
jQuery(function($){
   $("<a />", { 
      style: "cursor: pointer", 
      click: function() {
        alert('overriding the default action');
        return false;
      },
      text: "Test"
   }).prependTo("body");
});
</script>

Solution 2:

You have a couple of different questions here

When exactly the $(document).ready callback is executed?

It is executed as soon as the DOM is fully loaded. NOT when everything (such as images) are finished downloading like .load() would be. It is (in general) before that, basically it is when the page its self is built.

What I would like to know is when exactly the callback will execute

When it is clicked.

is it possible for the user to click on the anchor (the document has been shown in the browser) but the event hasn't been attached yet.

Yes, it is possible. But putting it in the .ready() give you the best chance that it will not. There are only 2 ways to do it to be 'more sure' that it will not. These are actually using the 'onclick' on the link its self, and putting the javascript directly after the link (and not in the .ready()) so that is executed immediately after the link is created.

Also, there is no difference between how the 2 code samples you provided will work. However, in the second one you do not need to put the code in the .ready(), because it exists after the link, it will always be executed after the link has been created. If you removed it from the .ready() it would be the first of the 2 ways I described above.

Additionally, instead of putting 'return false;' in your callback, it is better to use .preventDefault() and .stopPropagation() this will let you specify if you want to prevent the default action or stop the event from bubbling, or both.

Solution 3:

It depends on many things. If you have chunked encoding for example it is possible that a user will get a chunk but because the document is not ready yet the the listener will not be attached.

The jQuery ready event is the DOMContentLoaded event in W3C compliant browsers (standardized in the HTML5 specification), and some alternatives of this in others (like readystate in IE).

DOMContentLoaded (MDC)

Fired at the page's Document object when parsing of the document is finished. By the time this event fires, the page's DOM is ready.

Because this happens before rendering it would be a solid assumption that a callback executed after this event will be able to prevent user interaction on a not-ready page.

But as as Peter Michaux pointed out in his article due the the differences of how browsers implement this event "a robust technique for early enlivenment is not possible across the big four browsers."

So I would say that you can't rely 100% on jQuery ready event, but most of the time it will work just fine.

Solution 4:

In YUI, there are the methods onContentReady() and onAvailable(). unfortunately there is no equivalent to that in jQuery. However there is a plugin that was inspired by them:

http://www.thunderguy.com/semicolon/2007/08/14/elementready-jquery-plugin/

This should allow you to bind the events to the anchor before the DOM is fully loaded.