511

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

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
TIMEX
  • 217,272
  • 324
  • 727
  • 1,038
  • 4
    If you want to reproduce the jQuery's `$(document).ready()` event without using any library, give a look to this: http://stackoverflow.com/questions/1795089/need-help-with-jquery-to-javascript/1795167#1795167 – Christian C. Salvadó Feb 21 '10 at 05:47
  • @OP: check out page 89 of Pro JavaScript Techniques for a vanilla JavaScript implementation of `$(document).ready()` - http://books.google.com/books?id=GgJN2CC_2s4C&lpg=PP1&dq=pro%20javascript%20techniques&pg=PA89#v=onepage&q=&f=false . It also uses the `addEvent` event binding abstraction written by Dean Edwards, the code of which is also in the book :) – Russ Cam Feb 21 '10 at 17:57
  • 4
    possible duplicate of [$(document).ready equivalent without jQuery](http://stackoverflow.com/questions/799981/document-ready-equivalent-without-jquery) – Qantas 94 Heavy Mar 19 '14 at 13:11

9 Answers9

748

This works perfectly, from ECMA. The snippet is all you need, but if you want to dig more and explore other options check this detailed explanation.

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:

// 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 docs for details.

sospedra
  • 11,694
  • 3
  • 18
  • 26
  • 9
    @Deerloper Nope, just tried it on Chrome console - nothing happened: `document.addEventListener("DOMContentLoaded",function(){console.log(123)})` try it now – oriadam Sep 11 '16 at 09:54
  • 2
    Support of **DOMContentLoaded** in browsers : http://caniuse.com/domcontentloaded – Guillaume Husta Sep 28 '17 at 08:27
  • I have discovered a weird IE11 scenario where when I use a resize function it doesn't execute properly because it uses jquery to do a bunch of calculations... but if i wrap it (in doc ready inside window.addevent) like so, appears to be just fine. `window.addEventListener("DOMContentLoaded", function (event) { $(document).ready(function () { alignBody(); }); });`. Is this normal, because it feels like an evil hack? – petrosmm Apr 27 '20 at 15:22
46

This does not answer the question nor does it show any non-jQuery code. See @ sospedra's answer below.

The nice thing about $(document).ready() is that it fires before window.onload. The load function waits until everything is loaded, including external assets and images. $(document).ready, however, fires when the DOM tree is complete and can be manipulated. If you want to acheive DOM ready, without jQuery, you might check into this library. Someone extracted just the ready part from jQuery. Its nice and small and you might find it useful:

domready at Google Code

Devs love ZenUML
  • 9,490
  • 7
  • 41
  • 55
Doug Neiner
  • 62,310
  • 11
  • 103
  • 117
  • 4
    DomReady code network! via @CMS on github: https://github.com/cms/domready/network – Kzqai Aug 23 '11 at 21:59
  • 103
    This does not answer the question nor does it show any non-jQuery code. How did it get so many upvotes? – Daniel W. Nov 27 '18 at 16:52
  • 3
    @DanielW. Because it's simple and practical. Most of us came here looking for a way to make sure DOM is ready to be used by javascript code. – abarazal Dec 04 '19 at 21:18
  • 11
    Yeah but some of us came here for an actual answer. – Slbox Jun 07 '20 at 20:26
  • 3
    Pretty bad answer - ignores the OP question. Some of us don't want to use jQuery for many reasons. – Sean Haddy Aug 27 '20 at 01:17
46

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);
Thank you
  • 107,507
  • 28
  • 191
  • 224
44

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).

function domReady(fn) {
  // If we're early to the party
  document.addEventListener("DOMContentLoaded", fn);
  // If late; I mean on time.
  if (document.readyState === "interactive" || document.readyState === "complete" ) {
    fn();
  }
}

domReady(() => console.log("DOM is ready, come and get it!"));

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);
  }
});
CTS_AE
  • 7,990
  • 6
  • 43
  • 51
24

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

function ready(fn) {
  if (document.readyState != 'loading') {
    fn();
  } else if (document.addEventListener) {
    document.addEventListener('DOMContentLoaded', fn);
  } else {
    document.attachEvent('onreadystatechange', function() {
      if (document.readyState != 'loading')
        fn();
    });
  }
}

// test
window.ready(function() {
    alert('it works');
});

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.

online Thomas
  • 7,441
  • 5
  • 32
  • 67
  • 1
    Yes, this is the best answer in my opinion. Easy to read, and it executes the code even if the DOM is already loaded. The only thing I would add is to remove the eventlistener after the event is fired. – elliottregan Apr 24 '19 at 22:28
15

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 );
}
Zigri2612
  • 1,832
  • 16
  • 30
  • 1
    New jQuery dropped support for older browsers and now they only have `DOMContentLoaded` and `load` events using `addEventListener`, and first that fire remove both listeners, so it don't fire two times. – jcubic Dec 06 '18 at 12:05
9

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.

Brian Campbell
  • 289,867
  • 55
  • 346
  • 327
  • 42
    For the many downvoters of this answer (and the others below): when this question was asked, it said simply: "What is $(document).ready() in javascript? Not jquery. What is it?" It sounded like he was asking what that meant in plain vanilla JavaScript with no jQuery loaded. In my answer, I attempted to answer that question, as well as give the closest easy answer for plain-vanilla JavaScript with no jQuery or other libraries in case that's what he meant. Note that all extra context was added by other people guessing at what the question was asking, not the original poster. – Brian Campbell Sep 12 '13 at 05:20
8

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

onDOMContentLoaded = (function(){ console.log("DOM ready!") })()

onload = (function(){ console.log("Page fully loaded!") })()

onloadeddata = (function(){ console.log("Data loaded!") })()

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:

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

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.

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

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*/   })()
NVRM
  • 6,477
  • 1
  • 51
  • 60
  • Could an IIFE trigger before the DOM is finished loading elements after it? – CTS_AE Dec 03 '18 at 21:15
  • Sure, it is just a function, an anonymous function, in a closure. – NVRM Dec 03 '18 at 21:24
  • noobie question: what's the difference (other than a smaller syntax and less clear full context intent) of this from using the event listener? – cregox Jun 22 '20 at 06:13
  • eventListeners are more flexible, a major difference is we can declare many listener on the same event, but on this case that doesn't matter since the event is onload, it will trigger only one time. – NVRM Jun 22 '20 at 13:37
0

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>
joan16v
  • 4,551
  • 2
  • 44
  • 45