Replace the jQuery Document Ready Function with JavaScript

Julian Kühnel
Share

The jQuery document ready ($(document).ready()) method was implemented to execute code when the DOM is fully loaded. Since it executes the given function when all DOM elements are available, you can be sure that trying to access or manipulate elements will work.

Before jQuery 3.0, the typical usage with a anonymous function looked like this:

$(document).ready(function() {
  // Handler for .ready() called.
});

jQuery 3.0 ready() Changes

Before the release of version 3, there were several ways you could call the ready method:

  • on the document element: $(document).ready(handler);
  • on an empty element: $().ready(handler);
  • or directly (i.e. not on a specific element): $(handler);

All above named variants are functionally equivalent. The specified handler will be called when the DOM is fully loaded, no matter on which element it was called. In other words, calling it on an image element $("img") versus the document element doesn’t indicate that the callback is fired when the specified element is loaded. Instead, it will be called when the entire DOM is fully loaded.

In jQuery 3.0, all other syntax methods except $(handler); are deprecated. The official justification is:

This is because the selection has no bearing on the behavior of the .ready() method, which is inefficient and can lead to incorrect assumptions about the method’s behavior.

Difference Between the Ready and Load Events

The ready event is fired when the DOM is fully loaded and accesses to elements are safe. The load event, on the other hand, is fired after the DOM and all assets have loaded.

The load event can be used as follows:

$(window).on("load", function(){
  // Handler when all assets (including images) are loaded
});

This waits not only for the DOM to be ready for interaction but also for images to be completely loaded (which can take time, depending on the image sizes).

For normal DOM manipulations you’ll probably not need the load event, But it might be the right choice if you’d like to show a loading spinner until all assets are loaded, for example, or if you’d like to do some calculations with image sizes.

You Probably Don’t Need jQuery.ready()

The ready method makes sure that code is only executed when all DOM elements are safe to be manipulated. But what does this mean? When you’re executing JavaScript code inside the <head> section of an HTML document then this would make sure that the code is executed when the browser has loaded all following elements (e.g. the <body> element) too:

<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <title>.ready() tutorial</title>
    <script src="https://cdn.jsdelivr.net/jquery/latest/jquery.min.js"></script>
    <script>
      $(function(){ // .ready() callback, is only executed when the DOM is fully loaded
        var length = $("p").length;
        // The following will log 1 to the console, as the paragraph exists.
        // This is the evidence that this method is only called when the
        // DOM is fully loaded
        console.log(length);
      });
    </script>
  </head>
  <body>
    <p>I'm the content of this website</p>
  </body>
</html>

If you’re executing JavaScript as the last thing inside the <body>, you probably don’t need to wrap it inside ready(), as all elements you might try to manipulate or access are already loaded:

<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <title>.ready() tutorial</title>
  </head>
  <body>
    <p>I'm the content of this website</p>
    <script src="https://cdn.jsdelivr.net/jquery/latest/jquery.min.js"></script>
    <script>
      var length = $("p").length;
      // The following will log 1 to the console, as the paragraph exists.
      console.log(length);
    </script>
  </body>
</html>

Plain JavaScript ready() Alternative

For modern browsers, and IE9+, you can listen for the DOMContentLoaded event:

document.addEventListener("DOMContentLoaded", function(){
  // Handler when the DOM is fully loaded
});

But, note that the callback will not be executed if the event has already fired. To make sure the callback is always run, jQuery checks the readyState of a document (reference) and, if it’s already complete, executes the callback immediately:

var callback = function(){
  // Handler when the DOM is fully loaded
};

if (
    document.readyState === "complete" ||
    (document.readyState !== "loading" && !document.documentElement.doScroll)
) {
  callback();
} else {
  document.addEventListener("DOMContentLoaded", callback);
}

You could also include the domReady library, which has already implemented this solution.

Older versions of Internet Explorer

For IE versions less than or equal 8, you could use the onreadystatechange event to detect the readyState of a document:

document.attachEvent("onreadystatechange", function(){
  // check if the DOM is fully loaded
  if(document.readyState === "complete"){
    // remove the listener, to make sure it isn't fired in future
    document.detachEvent("onreadystatechange", arguments.callee);
    // The actual handler...
  }
});

Alternatively you could use the load event, like jQuery does, as this will work in any browser. This also results in a time delay, as it’ll wait for all assets to be loaded. Note that you’ll also have to check the readyState in this solution, like explained above, to make sure the callback will still be executed even if the event has already fired.

Conclusion

If you’re searching for a plain JavaScript alternative for the ready method you can proceed with the DOMContentLoaded event. If your system requirements include IE < 9 you can use the onreadystatechange event.

If you’re using jQuery in your project you can safely proceed with using the jQuery document ready function, but remember to avoid using the (deprecated) ready() method on elements (e.g. $(document).ready()) as mentioned earlier.

And lastly, don’t forget that in many situations you may not need any of these solutions — just move your JavaScript before the closing </body> tag and you can be sure that the DOM has finished loading!