52

I know I can use different frameworks like prototype or jQuery to attach a function to the window.onload, but's not what I'm looking for.

I need something like .readyState so that I can do something like this:

if(document.isReady){
  var id = document.getElem ...
}

is there any other way than using what the frameworks do?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
kristian nissen
  • 2,809
  • 5
  • 44
  • 68
  • 10
    Detecting DOM ready reliably cross-browser is not trivial. Why don't you want to use one of the proven frameworks? – Mauricio Scheffer Jul 30 '09 at 14:27
  • 2
    i would recommend looking at domassistant - it is very lightweight library. or, check d-lite for extra lightweight set of functions. – dusoft Jul 30 '09 at 14:31
  • I have been asked not to, basically. – kristian nissen Jul 31 '09 at 06:31
  • 1
    See [my answer](http://stackoverflow.com/questions/2732171/javascript-dom-ready-without-an-entire-framework/4830662#4830662) on a similar question for the link to a cross-browser DOMReady object. – Victor Jan 28 '11 at 16:38
  • you may want to reconsider the correct answer. – Patrick W. McMahon Sep 20 '14 at 18:41
  • agree with @PatrickW.McMahon, the correct answer should be, as of 2017, to use the standard `document.addEventListener('DOMContentLoaded' ...`, as suggested below (almost hidden), instead of a library. – Pierre H. Sep 08 '17 at 14:45

11 Answers11

44

Edit: As the year 2018 comes upon us, I think it's safe to listen for the DOMContentLoaded event.

function fireOnReady() { /* ... */ }
if (document.readyState === 'complete') {
    fireOnReady();
} else {
    document.addEventListener("DOMContentLoaded", fireOnReady);
}

Please note, the event will only fire once when your page loads! If you have to support really old browsers, then check out the super lightweight script I put together below.



For historical reference only:



jQuery has an undocumented property called isReady which is used internally to determine whether the DOM ready event has fired:

if($.isReady) {
    // DOM is ready
} else {
    // DOM is not yet ready
}

I started at 1.5.2 went back as far as 1.3.2 and the property is there. While undocumented, I would say that you can rely on this property in future versions of jQuery. Edit: And a year later - v1.7.2, they still use $.isReady - still undocumented, so please use at your own risk. Be careful when upgrading.

Edit: v1.9, they still use $.isReady - still undocumented

Edit: v2.0, with all of it's "major" changes, still uses $.isReady - still undocumented

Edit: v3.x still uses $.isReady - still undocumented

Edit: As several people have pointed out, the above does not really answer the question. So I have just created a mini DOM ready snippet which was inspired by Dustin Diaz's even smaller DOM ready snippet. Dustin created a neat way to check the document readyState with something similar to this:

if( !/in/.test(document.readyState) ) {
    // document is ready
} else {
    // document is NOT ready
}

The reason this works is because the browser has 3 loading states: "loading", "interactive", and "complete" (older WebKit also used "loaded", but you don't have to worry about that any more). You will notice that both "loading" and "interactive" contain the text "in"... so if the string "in" is found inside of document.readyState, then we know we are not ready yet.

Ryan Wheale
  • 26,022
  • 8
  • 76
  • 96
  • 3
    Not sure why the down vote. I explained that this is undocumented. Debugging this issue in future versions of jQuery would be extremely simple, and it's one of those self-describing variables that will never pass the "there's a better name for this" test and therefore will likely never get renamed. whatever... I wish people would explain down votes. – Ryan Wheale Aug 02 '12 at 02:58
  • 7
    This doesn't answer the question (OP doesn't want to use a framework). It does, however, provide a good answer to a question marked as "exact duplicate" of this one (+1 from me). http://stackoverflow.com/questions/8373910/in-jquery-how-do-i-check-if-the-dom-is-ready – Brent Bradburn Feb 03 '13 at 07:48
  • 1
    Upvoted- does not answer this question, but answers questions of many people ending up here. – bjedrzejewski Oct 07 '13 at 12:56
  • The requirement was to get dom ready without using a framework. Your example solves the problem but using a framework. This should be part of a different question asking how to get dom ready using JQuery but should not be a solution to the current question. Do not up vote something for solving another question. Only up vote when it solves the current question. – Patrick W. McMahon Oct 14 '14 at 17:37
  • 1
    @et al - This was one of my earliest answers on S.O. and I was not wise in my ways. Thanks to those who pointed out my shortsightedness, I have long since updated my answer to include a framework-less solution. – Ryan Wheale Oct 14 '14 at 18:54
  • Upvote for admitting shortsightedness and correcting it thereto. – Mac Dec 15 '14 at 20:39
  • Thank you for correcting your answer so that it meets the requirements of the question. – Patrick W. McMahon Jan 23 '15 at 17:03
32

While I usually advocate avoiding using frameworks unless necessary, I'd say using one in this case is perfectly fine. Here's jQuery:

$(function () {
    // do stuff after DOM has loaded
});

Note that it is NOT the same as an window.onload event, since onload executes first after other resources have been loaded (images etc.) The code I used in my example will execute when the DOM has finished loading, i.e., when the full HTML structure is available (not necessarily when images, CSS, etc. is available.)

If you want a checkable variable, you can set one in the ready-function:

var documentIsReady = false;
$(function () { documentIsReady = true; });

Of course you can find even more light-weight libraries than jQuery if all you want to do is to check for DOM-ready. But use a library in cases where different browsers behave very differently (this is one such case.)

Using some code from the DOMAssistant library, making your own "DOM is ready" function shouldn't be too hard:

var domLoaded = function (callback) {
    /* Internet Explorer */
    /*@cc_on
    @if (@_win32 || @_win64)
        document.write('<script id="ieScriptLoad" defer src="//:"><\/script>');
        document.getElementById('ieScriptLoad').onreadystatechange = function() {
            if (this.readyState == 'complete') {
                callback();
            }
        };
    @end @*/
    /* Mozilla, Chrome, Opera */
    if (document.addEventListener) {
        document.addEventListener('DOMContentLoaded', callback, false);
    }
    /* Safari, iCab, Konqueror */
    if (/KHTML|WebKit|iCab/i.test(navigator.userAgent)) {
        var DOMLoadTimer = setInterval(function () {
            if (/loaded|complete/i.test(document.readyState)) {
                callback();
                clearInterval(DOMLoadTimer);
            }
        }, 10);
    }
    /* Other web browsers */
    window.onload = callback;
};

Not tested, but it should work. I simplified it from DOMAssistant, because DOMAssistant allows multiple callbacks and has checking to make sure you can't add the same function twice etc.

Blixt
  • 49,547
  • 13
  • 120
  • 153
  • 4
    It's the only thing I need from a framework, everything else it has to serve, I don't need, so if possible, I would prefer not to use a framework in this case, otherwise I would go with jquery – kristian nissen Jul 31 '09 at 06:32
  • Okay, I added some simplified code from DOMAssistant, you could try that. According to their site it should work in all the major browsers. http://www.domassistant.com/documentation/DOMAssistantLoad-module.php – Blixt Jul 31 '09 at 07:32
  • 1
    My code will call `callback` up to two times (since `window.onload` should execute in all browsers.) When handling the event, check if `callback` has already been called and return if it has (this is what DOMAssistant does but I removed that part.) – Blixt Jul 31 '09 at 07:36
  • 1
    changing the value of `window.onload` without respect the actual value can produce unexpected behaviors in the code of other scripts. Also we can not call `domLoaded` twice since only the last one will be used. – fguillen Oct 07 '11 at 14:04
  • 1
    This code worked for me! Except I had to use `else if` or firefox would fire twice. – jisaacstone Nov 30 '11 at 01:15
  • `if (/loaded|complete/i.test(document.readyState)) { callback(); return; }` should be at the top of the function in case the page has already been loaded. – enyo Aug 25 '12 at 22:18
  • This, unlike jQuery's domready, will not add callbacks! At least for the window.onload, it will only replace existing callbacks with a new one! – Kzqai Oct 24 '12 at 23:33
  • +1 for not saying `just use jquery or x library` I hate when people do this. – Vitim.us May 05 '13 at 23:27
  • `DOMContentLoaded` fires one time when the DOM is fully loaded and parsed. all the extra stuff you're doing is not needed. – Patrick W. McMahon Oct 14 '14 at 17:49
32

In the 5 years that have passed since this question was asked DOMContentLoaded has become a universally supported event, and you can just use that.

document.addEventListener('DOMContentLoaded', function() {
    //.. do stuff ..
}, false);
Damon Smith
  • 1,770
  • 18
  • 24
  • I was just getting ready make a comment about DOMContentLoaded myself. Since there aren't any dissenting opinions here, I assume this is the right way to go? – Nocturno Aug 27 '15 at 18:19
  • This is supported in every modern browser http://caniuse.com/#search=DOMContentLoaded – str Oct 31 '15 at 14:47
  • Why did you post this a year after people had already commented on the addEventListener(). You have not added anything that other answers prior to yours had already done. – Patrick W. McMahon Oct 19 '16 at 17:50
  • Well, sorry Patrick I know it seems like I deliberately re-answered this question in the same way as you in order to steal your internet points but I honestly didn't see your answer. I scrolled through at the time and thought well that's funny, no one has pointed out that this is no longer an issue that requires 3rd party code. Which is still, I think, the part of my answer that people are upvoting - that this is now universally supported. – Damon Smith Oct 23 '16 at 02:11
11

i've updated the code of DOMAssistant library it works fine with me

var domReady = (function (){
  var arrDomReadyCallBacks = [] ;
  function excuteDomReadyCallBacks(){
       for (var i=0; i < arrDomReadyCallBacks.length; i++) {
         arrDomReadyCallBacks[i]();
       }
       arrDomReadyCallBacks = [] ;
  }

  return function (callback){
    arrDomReadyCallBacks.push(callback);
     /* Mozilla, Chrome, Opera */
      if (document.addEventListener ) {
          document.addEventListener('DOMContentLoaded', excuteDomReadyCallBacks, false);
      }
    /* Safari, iCab, Konqueror */
    if (/KHTML|WebKit|iCab/i.test(navigator.userAgent)) {
        browserTypeSet = true ;
        var DOMLoadTimer = setInterval(function () {
            if (/loaded|complete/i.test(document.readyState)) {
                //callback();
                excuteDomReadyCallBacks();
                clearInterval(DOMLoadTimer);
            }
        }, 10);
    }
    /* Other web browsers */

    window.onload = excuteDomReadyCallBacks;
}
})()
Yehia
  • 386
  • 2
  • 9
  • why the down voting ? the code is tested with ie 8 ,firefox and chrome . – Yehia Dec 01 '14 at 21:19
  • Your example is a Rube Goldberg Machine. Remember in programming the KISS method. There are simple one liner solutions to solving the problem without the need of extra processing. Please add more documentation as to why your solution is needed over simpler one line solutions. Code snippets without documents don't get a lot of up votes. – Patrick W. McMahon Jan 23 '15 at 17:09
10
document.addEventListener("DOMContentLoaded", function(e){
    console.log("dom ready");//output to web browser console
});

no JQuery needed for this. There is no need to pass the 3rd parameter on a DOMContentLoaded as this event has no parent to traverse the event. Also no need to get all fancy with what everyone else is saying. This will tell you when the DOM is fully loaded and ready to use. I LOLed when i noticed the DOM assistant lib. That lib is absolutely useless.

The DOMContentLoaded event is fired when the document has been completely loaded and parsed, without waiting for stylesheets, images, and subframes to finish loading

addEventListener() is a great function for checking any event including DOM ready status. When using "DOMContentLoaded" the 3rd parameter in addEventListener() is not needed as this trigger has no parent item to pass the event too. In my above example you will notice the 2nd parameter is an anonymous function. You can also pass the name of a function into the 2nd parameter.

document.addEventListener([(string)event trigger], [function],[(boolean)traverse DOM tree]);

Another benefit to using this over JQuery is this will not break when you update JQuery.

Patrick W. McMahon
  • 3,488
  • 1
  • 20
  • 31
10

Check out this demo from microsoft. -> http://ie.microsoft.com/testdrive/HTML5/DOMContentLoaded/Default.html And here is the gist of the code that allows you to run JS on DOM ready...

(function () {
    function load2(){
        // put whatever you need to load on DOM ready in here
        document.getElementById("but3").addEventListener("click", doMore, false);
    }
    if (window.addEventListener) {
        window.addEventListener('DOMContentLoaded', load2, false);
    } else {
        window.attachEvent('onload', load2);
    }
} ());

Here is the some of the javascript source for the demo.. http://ie.microsoft.com/testdrive/Includes/Script/ReturnAndShareControls.js

It works well. Nice!!.. on google Chrome and IE 9.

Randy Skretka
  • 3,488
  • 3
  • 22
  • 14
6

jQuery doesn't use window.onload.

$(document).ready() waits until the DOM has loaded and can be traversed (the rest of the content may or may not be loaded by that point).

If you pull up the source for jQuery and sort through the mess, you'll find the work is done by the bindReady() method which has several different implementations for different browsers and only when all of those implementations fail does it fall back on listening for the load event for the window.

Paul D. Waite
  • 96,640
  • 56
  • 199
  • 270
Justin Niessner
  • 242,243
  • 40
  • 408
  • 536
  • @PatrickW.McMahon - I didn't suggest using jQuery in my answer. If you read it closer, I told the OP to read the source of jQuery to see how they're doing their ready detection so that he could mimic it. – Justin Niessner Sep 30 '14 at 20:21
  • Why tell some one to dig into jQuery code for something when you can link them to w3schools documentation for getting DOM state? It takes less time to do and no need to dig into thousands of lines of JQuery and following JQuery flags and triggers just to find out they wrapped the w3school demo into a JQuery function. The simple solution is normally the best solution. A programmers time is valuable. Pick the most effective solution. By the time he had dug into the JQuery framework he may as well just used JQuery. – Patrick W. McMahon Oct 14 '14 at 17:55
  • @PatrickW.McMahon - No need to look at thousands of lines. I told the OP in my answer exactly which method to look at. W3Schools isn't going to show the OP the best way to implement identical functionality in each browser. If you want to be a better developer, you learn from good code. W3Schools certainly doesn't have good code. – Justin Niessner Oct 14 '14 at 18:04
  • @Justin Niessner - W3School is the governing body for the web. If you think they're not providing good quality code to the standards they made then we have bigger problems on our hands. The members that run W3School are the same people that are working on the new HTML5 standards. – Patrick W. McMahon Jan 23 '15 at 17:13
  • @PatrickW.McMahon - W3School is certainly NOT the governing body of the web. That would be the W3C (World Wide Web Consortium) http://www.w3.org/ W3Schools has gotten better than it was, but there are still issues. Check out http://www.w3fools.com for more info. – Justin Niessner Jan 23 '15 at 17:37
  • A lot of the people working for W3School are members of W3C. I'm not saying all members of W3C work for W3School, but W3School has many of its employees as members of W3C. So they often have the information as its being published by W3C. I was not able to find them on the list http://www.w3.org/Consortium/Member/List but I beleave they are under a corporate name. Not by the sites name. – Patrick W. McMahon Jan 23 '15 at 17:57
  • @PatrickW.McMahon - W3Schools was created and is still owned by Refsnes Data. They are not a member of the W3C. Furthermore, it is publicly stated that W3Schools is, in no way, affiliated with the W3C. If you have a list of W3C members employed by Refsnes Data, I'd be very appreciative to see it. – Justin Niessner Jan 23 '15 at 20:05
3

This is actually one of the biggest reasons most people use frameworks like jQuery because the solution to this is not consistent across browsers.

Scott Fox
  • 830
  • 9
  • 8
  • 2
    I know, and I am a heavy user of jquery myself, but in this case I do not want to rely on a framework, I have been asked to avoid it. – kristian nissen Jul 31 '09 at 06:33
  • 2
    I would suggest possibly looking at the source to jQuery and porting *just* the code you want into your project. – Scott Fox Jul 31 '09 at 19:57
  • 1
    getting DOM ready is a single line `document.addEventListener("DOMContentLoaded", function(e){/*dom ready do something*/});` how is that so hard that you need to use a framework to get dom ready? – Patrick W. McMahon Oct 14 '14 at 17:47
1

Try this:
Link: onDomReady at GitHub or the source below:

if(document.ondomready == undefined) {
    document.ondomready = {};
    document.ondomready = null;
} else {
    document.ondomready=document.ondomready;
}
var oldonload=document.onload;
var isLaunched = 0;
document.onload = function() {  
    if(oldonload !== null) {
        oldonload.call();
    }
};
document.addEventListener("DOMContentLoaded", function onDom(evt) {
    var olddomready = document.ondomready;
    if(olddomready !== null) {
        if(isLaunched == 0) {
            olddomready.call(evt);
            isLaunched == 1;
            //We now launched the mapped DOMContentLoaded Event
        } else {
            //We already launched DOMContentLoaded Event
        }
    }
}, false);

I've already tested this on Opera 11.x/12.x. Not yet tested on others. Let me know if they do.

Note: I haven't yet uploaded the repository, but I will soon in my spare time.

dsrdakota
  • 2,415
  • 1
  • 15
  • 10
0

If you want smaller libs which does only particular things, you could use libs in microjs. For the question at hand DOMStatic libs ready method can be used.

Jerome Anthony
  • 7,823
  • 2
  • 40
  • 31
0

It seems this question was asked a reallly long time ago. Today we now have document.readyState, and even an event that goes with it.

To achieve the equivalent of:

if(document.isReady){
  var id = document.getElem ...
}

Use the following:

const doTask = () => {
  var id = document.getElem ....
}

if (document.readyState !== 'loading') {
  // in case we missed the `loading` state, start running the
  // task now...
  doTask();
} else {
  //  otherwise register a listener to be notified of the next state
  document.addEventListener('readystatechange', event => {
    if (event.target.readyState === 'interactive') {
      doTask();
    }
  });
}

The other answers which use window:DOMContentLoaded event, will receive that event after the above event listener runs, which means that using the readystatechange event allows you to start working on the DOM before DOMContentLoaded is fired, while still being able to interact with DOM elements.

The MDN docs provide an example here. Just in case the example goes away, here it is:

const log = document.querySelector('.event-log-contents');
const reload = document.querySelector('#reload');

reload.addEventListener('click', () => {
  log.textContent ='';
  window.setTimeout(() => {
      window.location.reload(true);
  }, 200);
});

window.addEventListener('load', (event) => {
    log.textContent = log.textContent + 'load\n';
});

document.addEventListener('readystatechange', (event) => {
    log.textContent = log.textContent + `readystate: ${document.readyState}\n`;
});

document.addEventListener('DOMContentLoaded', (event) => {
    log.textContent = log.textContent + `DOMContentLoaded\n`;
});
<div class="controls">
  <button id="reload" type="button">Reload</button>
</div>

<div class="event-log">
  <label>Event log:</label>
  <textarea readonly class="event-log-contents" rows="8" cols="30"></textarea>
</div>
smac89
  • 39,374
  • 15
  • 132
  • 179