[javascript] What is the non-jQuery equivalent of '$(document).ready()'?

What is the non-jQuery equivalent of $(document).ready()?

This question is related to javascript jquery

The answer is


The easiest way in recent browsers would be to use the appropriate GlobalEventHandlers, onDOMContentLoaded, onload, onloadeddata (...)

_x000D_
_x000D_
onDOMContentLoaded = (function(){ console.log("DOM ready!") })()_x000D_
_x000D_
onload = (function(){ console.log("Page fully loaded!") })()_x000D_
_x000D_
onloadeddata = (function(){ console.log("Data loaded!") })()
_x000D_
_x000D_
_x000D_

The DOMContentLoaded event is fired when the initial HTML document has been completely loaded and parsed, without waiting for stylesheets, images, and subframes to finish loading. A very different event load should be used only to detect a fully-loaded page. It is an incredibly popular mistake to use load where DOMContentLoaded would be much more appropriate, so be cautious.

https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded

The function used is an IIFE, very useful on this case, as it trigger itself when ready:

https://en.wikipedia.org/wiki/Immediately-invoked_function_expression

It is obviously more appropriate to place it at the end of any scripts.

In ES6, we can also write it as an arrow function:

_x000D_
_x000D_
onload = (() => { console.log("ES6 page fully loaded!") })()
_x000D_
_x000D_
_x000D_

The best is to use the DOM elements, we can wait for any variable to be ready, that trigger an arrowed IIFE.

The behavior will be the same, but with less memory impact.

_x000D_
_x000D_
footer = (() => { console.log("Footer loaded!") })()
_x000D_
<div id="footer">
_x000D_
_x000D_
_x000D_

In many cases, the document object is also triggering when ready, at least in my browser. The syntax is then very nice, but it need further testings about compatibilities.

document=(()=>{    /*Ready*/   })()

There is a standards based replacement,DOMContentLoaded that is supported by over 90%+ of browsers, but not IE8 (So below code use by JQuery for browser support):

document.addEventListener("DOMContentLoaded", function(event) { 
  //do work
});

jQuery's native function is much more complicated than just window.onload, as depicted below.

function bindReady(){
    if ( readyBound ) return;
    readyBound = true;

    // Mozilla, Opera and webkit nightlies currently support this event
    if ( document.addEventListener ) {
        // Use the handy event callback
        document.addEventListener( "DOMContentLoaded", function(){
            document.removeEventListener( "DOMContentLoaded", arguments.callee, false );
            jQuery.ready();
        }, false );

    // If IE event model is used
    } else if ( document.attachEvent ) {
        // ensure firing before onload,
        // maybe late but safe also for iframes
        document.attachEvent("onreadystatechange", function(){
            if ( document.readyState === "complete" ) {
                document.detachEvent( "onreadystatechange", arguments.callee );
                jQuery.ready();
            }
        });

        // If IE and not an iframe
        // continually check to see if the document is ready
        if ( document.documentElement.doScroll && window == window.top ) (function(){
            if ( jQuery.isReady ) return;

            try {
                // If IE is used, use the trick by Diego Perini
                // http://javascript.nwbox.com/IEContentLoaded/
                document.documentElement.doScroll("left");
            } catch( error ) {
                setTimeout( arguments.callee, 0 );
                return;
            }

            // and execute any waiting functions
            jQuery.ready();
        })();
    }

    // A fallback to window.onload, that will always work
    jQuery.event.add( window, "load", jQuery.ready );
}

In plain vanilla JavaScript, with no libraries? It's an error. $ is simply an identifier, and is undefined unless you define it.

jQuery defines $ as it's own "everything object" (also known as jQuery so you can use it without conflicting with other libraries). If you're not using jQuery (or some other library that defines it), then $ will not be defined.

Or are you asking what the equivalent is in plain JavaScript? In that case, you probably want window.onload, which isn't exactly equivalent, but is the quickest and easiest way to get close to the same effect in vanilla JavaScript.


The body onLoad could be an alternative too:

<html>
<head><title>Body onLoad Exmaple</title>

<script type="text/javascript">
    function window_onload() {
        //do something
    }
</script>

</head>
<body onLoad="window_onload()">

</body>
</html>

A little thing I put together

domready.js

(function(exports, d) {
  function domReady(fn, context) {

    function onReady(event) {
      d.removeEventListener("DOMContentLoaded", onReady);
      fn.call(context || exports, event);
    }

    function onReadyIe(event) {
      if (d.readyState === "complete") {
        d.detachEvent("onreadystatechange", onReadyIe);
        fn.call(context || exports, event);
      }
    }

    d.addEventListener && d.addEventListener("DOMContentLoaded", onReady) ||
    d.attachEvent      && d.attachEvent("onreadystatechange", onReadyIe);
  }

  exports.domReady = domReady;
})(window, document);

How to use it

<script src="domready.js"></script>
<script>
  domReady(function(event) {
    alert("dom is ready!");
  });
</script>

You can also change the context in which the callback runs by passing a second argument

function init(event) {
  alert("check the console");
  this.log(event);
}

domReady(init, console);

According to http://youmightnotneedjquery.com/#ready a nice replacement that still works with IE8 is

_x000D_
_x000D_
function ready(fn) {_x000D_
  if (document.readyState != 'loading') {_x000D_
    fn();_x000D_
  } else if (document.addEventListener) {_x000D_
    document.addEventListener('DOMContentLoaded', fn);_x000D_
  } else {_x000D_
    document.attachEvent('onreadystatechange', function() {_x000D_
      if (document.readyState != 'loading')_x000D_
        fn();_x000D_
    });_x000D_
  }_x000D_
}_x000D_
_x000D_
// test_x000D_
window.ready(function() {_x000D_
    alert('it works');_x000D_
});
_x000D_
_x000D_
_x000D_

improvements: Personally I would also check if the type of fn is a function. And as @elliottregan suggested remove the event listener after use.

The reason I answer this question late is because I was searching for this answer but could not find it here. And I think this is the best solution.


Now that it's 2018 here's a quick and simple method.

This will add an event listener, but if it already fired we'll check that the dom is in a ready state or that it's complete. This can fire before or after sub-resources have finished loading (images, stylesheets, frames, etc).

_x000D_
_x000D_
function domReady(fn) {_x000D_
  // If we're early to the party_x000D_
  document.addEventListener("DOMContentLoaded", fn);_x000D_
  // If late; I mean on time._x000D_
  if (document.readyState === "interactive" || document.readyState === "complete" ) {_x000D_
    fn();_x000D_
  }_x000D_
}_x000D_
_x000D_
domReady(() => console.log("DOM is ready, come and get it!"));
_x000D_
_x000D_
_x000D_

Additional Readings


Update

Here's some quick utility helpers using standard ES6 Import & Export I wrote that include TypeScript as well. Maybe I can get around to making these a quick library that can be installed into projects as a dependency.

JavaScript

export const domReady = (callBack) => {
  if (document.readyState === "loading") {
    document.addEventListener('DOMContentLoaded', callBack);
  }
  else {
    callBack();
  }
}

export const windowReady = (callBack) => {
  if (document.readyState === 'complete') {
    callBack();
  }
  else {
    window.addEventListener('load', callBack);
  }
}

TypeScript

export const domReady = (callBack: () => void) => {
  if (document.readyState === "loading") {
    document.addEventListener('DOMContentLoaded', callBack);
  }
  else {
    callBack();
  }
}

export const windowReady = (callBack: () => void) => {
  if (document.readyState === 'complete') {
    callBack();
  }
  else {
    window.addEventListener('load', callBack);
  }
}

Promises

export const domReady = new Promise(resolve => {
  if (document.readyState === "loading") {
    document.addEventListener('DOMContentLoaded', resolve);
  }
  else {
    resolve();
  }
});

export const windowReady = new Promise(resolve => {
  if (document.readyState === 'complete') {
    resolve();
  }
  else {
    window.addEventListener('load', resolve);
  }
});

This works perfectly, from ECMA

document.addEventListener("DOMContentLoaded", function() {
  // code...
});

The window.onload doesn't equal to JQuery $(document).ready because $(document).ready waits only to the DOM tree while window.onload check all elements including external assets and images.

EDIT: Added IE8 and older equivalent, thanks to Jan Derk's observation. You may read the source of this code on MDN at this link:

// alternative to DOMContentLoaded
document.onreadystatechange = function () {
    if (document.readyState == "interactive") {
        // Initialize your application or run some code.
    }
}

There are other options apart from "interactive". See the MDN link for details.