The question is so like a zillion others here and on the web - How to check if DOM has loaded in Javascript? But here's the catch:
- Without using a framework like jQuery etc;
- Without knowing if your script has been loaded via a statically placed
<script>
tag or via some other Javascript much later after the DOM has already loaded.
Can this be done more or less reliably and with cross-browser compatibility?
Added: Let me clarify: I'm writing a standalone .JS file which can be included in arbitrary webpages. I want to execute code AFTER the DOM has been loaded. But I don't know HOW my script will be included. It could be by placing a <script>
tag (in which case the traditional onload
or DOM-readiness solutions will work); or it could be loaded via AJAX or some other means, much later after the DOM is already loaded (so the previously mentioned solutions will never fire).
The document.readyState
property can be used to check if the document is ready:
if(document.readyState === "complete") {
//Already loaded!
}
else {
//Add onload or DOMContentLoaded event listeners here: for example,
window.addEventListener("onload", function () {/* your code here */}, false);
//or
//document.addEventListener("DOMContentLoaded", function () {/* code */}, false);
}
Firefox, Opera and Webkit-based browsers have a document-level event DOMContentLoaded
that you can listen for with document.addEventListener("DOMContentLoaded", fn, false)
.
It is more complicated in IE. What jQuery does in IE is watch onreadystatechange
on the document object for a particular readystate with a backup of the document.onload event. document.onload fires later than the DOM is ready (only when all images have finished loading) so it's only used as a backstop in case the earlier events don't work for some reason.
If you spend some time Googling, you will find code to do this. I figure the most vetted code to do this is in the large frameworks like jQuery and YUI so, even if I'm not using that framework, I look in their source code for techniques.
Here's the main part of jQuery 1.6.2 source for document.ready()
:
bindReady: function() {
if ( readyList ) {
return;
}
readyList = jQuery._Deferred();
// Catch cases where $(document).ready() is called after the
// browser event has already occurred.
if ( document.readyState === "complete" ) {
// Handle it asynchronously to allow scripts the opportunity to delay ready
return setTimeout( jQuery.ready, 1 );
}
// Mozilla, Opera and webkit nightlies currently support this event
if ( document.addEventListener ) {
// Use the handy event callback
document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
// A fallback to window.onload, that will always work
window.addEventListener( "load", 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", DOMContentLoaded );
// A fallback to window.onload, that will always work
window.attachEvent( "onload", jQuery.ready );
// If IE and not a frame
// continually check to see if the document is ready
var toplevel = false;
try {
toplevel = window.frameElement == null;
} catch(e) {}
if ( document.documentElement.doScroll && toplevel ) {
doScrollCheck();
}
}
},
This works for all browsers and is short and concise:
var execute = function () {
alert("executing code");
};
if ( !!(window.addEventListener) )
window.addEventListener("DOMContentLoaded", execute)
else // MSIE
window.attachEvent("onload", execute)
If relying on document.readyState
is ok, quick-and-dirty solution with polling:
(function() {
var state = document.readyState;
if(state === 'interactive' || state === 'complete') {
// do stuff
}
else setTimeout(arguments.callee, 100);
})();
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.Good thing is chrome, firefox, IE9, opera and safari supports it equally
document.addEventListener("DOMContentLoaded", function(event)
{
console.log("DOM fully loaded and parsed");
}
NOTE : Internet Explorer 8 supports the readystatechange event, which
can be used to detect when the DOM is ready.
Here is one way by running script at the bottom of the page. In addition by using the window.onload you can wait for all images/scripts to be loaded. Or you could simply place code at the bottom not waiting for images to be loaded.
<html>
<head>
</head>
<body>
</body>
<script language="text/javascript">
window.onload = (function (oldOnLoad) {
return function () {
if (oldOnLoad) {
olOnLoad(); //fire old Onload event that was attached if any.
}
// your code to run after images/scripts are loaded
}
})(window.onload);
// your code to run after DOM is loaded
</script>
</html>
Edited: for Vilx's Comment
Many onload bindings here is an example http://jsfiddle.net/uTF2N/3/