I have a script that uses $(document).ready, but it doesn't use anything else from jQuery. I'd like to lighten it up by removing the jQuery dependency.
How can I implement my own $(document).ready functionality without using jQuery? I know that using window.onload will not be the same, as window.onload fires after all images, frames, etc. have been loaded.
There is a standards based replacement,DOMContentLoaded that is supported by over 99% of browsers, though not IE8:
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 );
}
Edit:
2023 update, use this:
function ready(fn) {
if (document.readyState !== 'loading') {
fn();
return;
}
document.addEventListener('DOMContentLoaded', fn);
}
From: https://youmightnotneedjquery.com/
Here is a viable replacement for jQuery ready
function ready(callback){
// in case the document is already rendered
if (document.readyState!='loading') callback();
// modern browsers
else if (document.addEventListener) document.addEventListener('DOMContentLoaded', callback);
// IE <= 8
else document.attachEvent('onreadystatechange', function(){
if (document.readyState=='complete') callback();
});
}
ready(function(){
// do something
});
Taken from
https://plainjs.com/javascript/events/running-code-when-the-document-is-ready-15/
Another good domReady function here taken from https://stackoverflow.com/a/9899701/175071
As the accepted answer was very far from complete, I stitched together a "ready" function like jQuery.ready() based on jQuery 1.6.2 source:
var ready = (function(){
var readyList,
DOMContentLoaded,
class2type = {};
class2type["[object Boolean]"] = "boolean";
class2type["[object Number]"] = "number";
class2type["[object String]"] = "string";
class2type["[object Function]"] = "function";
class2type["[object Array]"] = "array";
class2type["[object Date]"] = "date";
class2type["[object RegExp]"] = "regexp";
class2type["[object Object]"] = "object";
var ReadyObj = {
// Is the DOM ready to be used? Set to true once it occurs.
isReady: false,
// A counter to track how many items to wait for before
// the ready event fires. See #6781
readyWait: 1,
// Hold (or release) the ready event
holdReady: function( hold ) {
if ( hold ) {
ReadyObj.readyWait++;
} else {
ReadyObj.ready( true );
}
},
// Handle when the DOM is ready
ready: function( wait ) {
// Either a released hold or an DOMready/load event and not yet ready
if ( (wait === true && !--ReadyObj.readyWait) || (wait !== true && !ReadyObj.isReady) ) {
// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
if ( !document.body ) {
return setTimeout( ReadyObj.ready, 1 );
}
// Remember that the DOM is ready
ReadyObj.isReady = true;
// If a normal DOM Ready event fired, decrement, and wait if need be
if ( wait !== true && --ReadyObj.readyWait > 0 ) {
return;
}
// If there are functions bound, to execute
readyList.resolveWith( document, [ ReadyObj ] );
// Trigger any bound ready events
//if ( ReadyObj.fn.trigger ) {
// ReadyObj( document ).trigger( "ready" ).unbind( "ready" );
//}
}
},
bindReady: function() {
if ( readyList ) {
return;
}
readyList = ReadyObj._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( ReadyObj.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", ReadyObj.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", ReadyObj.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();
}
}
},
_Deferred: function() {
var // callbacks list
callbacks = [],
// stored [ context , args ]
fired,
// to avoid firing when already doing so
firing,
// flag to know if the deferred has been cancelled
cancelled,
// the deferred itself
deferred = {
// done( f1, f2, ...)
done: function() {
if ( !cancelled ) {
var args = arguments,
i,
length,
elem,
type,
_fired;
if ( fired ) {
_fired = fired;
fired = 0;
}
for ( i = 0, length = args.length; i < length; i++ ) {
elem = args[ i ];
type = ReadyObj.type( elem );
if ( type === "array" ) {
deferred.done.apply( deferred, elem );
} else if ( type === "function" ) {
callbacks.push( elem );
}
}
if ( _fired ) {
deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );
}
}
return this;
},
// resolve with given context and args
resolveWith: function( context, args ) {
if ( !cancelled && !fired && !firing ) {
// make sure args are available (#8421)
args = args || [];
firing = 1;
try {
while( callbacks[ 0 ] ) {
callbacks.shift().apply( context, args );//shifts a callback, and applies it to document
}
}
finally {
fired = [ context, args ];
firing = 0;
}
}
return this;
},
// resolve with this as context and given arguments
resolve: function() {
deferred.resolveWith( this, arguments );
return this;
},
// Has this deferred been resolved?
isResolved: function() {
return !!( firing || fired );
},
// Cancel
cancel: function() {
cancelled = 1;
callbacks = [];
return this;
}
};
return deferred;
},
type: function( obj ) {
return obj == null ?
String( obj ) :
class2type[ Object.prototype.toString.call(obj) ] || "object";
}
}
// The DOM ready check for Internet Explorer
function doScrollCheck() {
if ( ReadyObj.isReady ) {
return;
}
try {
// If IE is used, use the trick by Diego Perini
// http://javascript.nwbox.com/IEContentLoaded/
document.documentElement.doScroll("left");
} catch(e) {
setTimeout( doScrollCheck, 1 );
return;
}
// and execute any waiting functions
ReadyObj.ready();
}
// Cleanup functions for the document ready method
if ( document.addEventListener ) {
DOMContentLoaded = function() {
document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
ReadyObj.ready();
};
} else if ( document.attachEvent ) {
DOMContentLoaded = function() {
// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
if ( document.readyState === "complete" ) {
document.detachEvent( "onreadystatechange", DOMContentLoaded );
ReadyObj.ready();
}
};
}
function ready( fn ) {
// Attach the listeners
ReadyObj.bindReady();
var type = ReadyObj.type( fn );
// Add the callback
readyList.done( fn );//readyList is result of _Deferred()
}
return ready;
})();
How to use:
<script>
ready(function(){
alert('It works!');
});
ready(function(){
alert('Also works!');
});
</script>
I am not sure how functional this code is, but it worked fine with my superficial tests. This took quite a while, so I hope you and others can benefit from it.
PS.: I suggest compiling it.
Or you can use http://dustindiaz.com/smallest-domready-ever:
function r(f){/in/.test(document.readyState)?setTimeout(r,9,f):f()}
r(function(){/*code to run*/});
or the native function if you only need to support the new browsers (Unlike jQuery ready, this won't run if you add this after the page has loaded)
document.addEventListener('DOMContentLoaded',function(){/*fun code to run*/})
Three options:
If script is the last tag of the body, the DOM would be ready before script tag executes
When the DOM is ready, "readyState" will change to "complete"
Put everything under 'DOMContentLoaded' event listener
onreadystatechange
document.onreadystatechange = function () {
if (document.readyState == "complete") {
// document is ready. Do your stuff here
}
}
Source: MDN
DOMContentLoaded
document.addEventListener('DOMContentLoaded', function() {
console.log('document is ready. I can sleep now');
});
Concerned about stone age browsers:
Go to the jQuery source code and use the ready function. In that case you are not parsing+executing the whole library you're are doing only a very small part of it.
Place your <script>/*JavaScript code*/</script> right before the closing </body> tag.
Admittedly, this might not suit everyone's purposes since it requires changing the HTML file rather than just doing something in the JavaScript file a la document.ready, but still...
Poor man's solution:
var checkLoad = function() {
document.readyState !== "complete" ? setTimeout(checkLoad, 11) : alert("loaded!");
};
checkLoad();
View Fiddle
Added this one, a bit better I guess, own scope, and non recursive
(function(){
var tId = setInterval(function() {
if (document.readyState == "complete") onComplete()
}, 11);
function onComplete(){
clearInterval(tId);
alert("loaded!");
};
})()
View Fiddle
I use this:
document.addEventListener("DOMContentLoaded", function(event) {
//Do work
});
Note: This probably only works with newer browsers, especially these: http://caniuse.com/#feat=domcontentloaded
It is year 2020 and <script> tag has defer attribute.
for example:
<script src="demo_defer.js" defer></script>
it specifies that the script is executed when the page has finished parsing.
https://www.w3schools.com/tags/att_script_defer.asp
2022 version
In 2022, all you need to do is put the defer attribute on your script, and load it in the head!
Reference: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-defer
<!doctype html>
<html>
<head>
<script src="/script.js" defer></script>
</head>
<body>
<p>In 2022, all you need to do is put the defer attribute on your script, and load it in the head!</p>
</body>
</html>
This question was asked quite a long time ago. For anyone just seeing this question, there is now a site called "you might not need jquery" which breaks down - by level of IE support required - all the functionality of jquery and provides some alternative, smaller libraries.
IE8 document ready script according to you might not need jquery
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();
});
}
Really, if you care about Internet Explorer 9+ only, this code would be enough to replace jQuery.ready:
document.addEventListener("DOMContentLoaded", callback);
If you worry about Internet Explorer 6 and some really strange and rare browsers, this will work:
domReady: function (callback) {
// Mozilla, Opera and WebKit
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", callback, false);
// If Internet Explorer, the event model is used
} else if (document.attachEvent) {
document.attachEvent("onreadystatechange", function() {
if (document.readyState === "complete" ) {
callback();
}
});
// A fallback to window.onload, that will always work
} else {
var oldOnload = window.onload;
window.onload = function () {
oldOnload && oldOnload();
callback();
}
}
},
Cross-browser (old browsers too) and a simple solution:
var docLoaded = setInterval(function () {
if(document.readyState !== "complete") return;
clearInterval(docLoaded);
/*
Your code goes here i.e. init()
*/
}, 30);
Showing alert in jsfiddle
I was recently using this for a mobile site. This is John Resig's simplified version from "Pro JavaScript Techniques". It depends on addEvent.
var ready = ( function () {
function ready( f ) {
if( ready.done ) return f();
if( ready.timer ) {
ready.ready.push(f);
} else {
addEvent( window, "load", isDOMReady );
ready.ready = [ f ];
ready.timer = setInterval(isDOMReady, 13);
}
};
function isDOMReady() {
if( ready.done ) return false;
if( document && document.getElementsByTagName && document.getElementById && document.body ) {
clearInterval( ready.timer );
ready.timer = null;
for( var i = 0; i < ready.ready.length; i++ ) {
ready.ready[i]();
}
ready.ready = null;
ready.done = true;
}
}
return ready;
})();
The jQuery answer was pretty useful to me. With a little refactory it fitted my needs well.
I hope it helps anybody else.
function onReady ( callback ){
var addListener = document.addEventListener || document.attachEvent,
removeListener = document.removeEventListener || document.detachEvent
eventName = document.addEventListener ? "DOMContentLoaded" : "onreadystatechange"
addListener.call(document, eventName, function(){
removeListener( eventName, arguments.callee, false )
callback()
}, false )
}
Here is the smallest code snippet to test DOM ready which works across all browsers (even IE 8):
r(function(){
alert('DOM Ready!');
});
function r(f){/in/.test(document.readyState)?setTimeout('r('+f+')',9):f()}
See this answer.
Just add this to the bottom of your HTML page...
<script>
Your_Function();
</script>
Because, HTML documents are parsed by top-bottom.
Most minimal and 100% working
I have picked the answer from PlainJS and it's working fine for me. It extends DOMContentLoaded so that it can be accepted at all the browsers.
This function is the equivalent of jQuery's $(document).ready() method:
document.addEventListener('DOMContentLoaded', function(){
// do something
});
However, in contrast to jQuery, this code will only run properly in modern browsers (IE > 8) and it won't in case the document is already rendered at the time this script gets inserted (e.g. via Ajax). Therefore, we need to extend this a little bit:
function run() {
// do something
}
// in case the document is already rendered
if (document.readyState!='loading') run();
// modern browsers
else if (document.addEventListener)
document.addEventListener('DOMContentLoaded', run);
// IE <= 8
else document.attachEvent('onreadystatechange', function(){
if (document.readyState=='complete') run();
});
This covers basically all possibilities and is a viable replacement for the jQuery helper.
Simplest way using pure JavaScript. Without jQuery:
document.addEventListener("DOMContentLoaded", function(event) {
// Your code to run since DOM is loaded and ready
});
It is worth looking in Rock Solid addEvent() and http://www.braksator.com/how-to-make-your-own-jquery.
Here is the code in case the site goes down
function addEvent(obj, type, fn) {
if (obj.addEventListener) {
obj.addEventListener(type, fn, false);
EventCache.add(obj, type, fn);
}
else if (obj.attachEvent) {
obj["e"+type+fn] = fn;
obj[type+fn] = function() { obj["e"+type+fn]( window.event ); }
obj.attachEvent( "on"+type, obj[type+fn] );
EventCache.add(obj, type, fn);
}
else {
obj["on"+type] = obj["e"+type+fn];
}
}
var EventCache = function(){
var listEvents = [];
return {
listEvents : listEvents,
add : function(node, sEventName, fHandler){
listEvents.push(arguments);
},
flush : function(){
var i, item;
for(i = listEvents.length - 1; i >= 0; i = i - 1){
item = listEvents[i];
if(item[0].removeEventListener){
item[0].removeEventListener(item[1], item[2], item[3]);
};
if(item[1].substring(0, 2) != "on"){
item[1] = "on" + item[1];
};
if(item[0].detachEvent){
item[0].detachEvent(item[1], item[2]);
};
item[0][item[1]] = null;
};
}
};
}();
// Usage
addEvent(window, 'unload', EventCache.flush);
addEvent(window, 'load', function(){alert("I'm ready");});
It's always good to use JavaScript equivalents as compared to jQuery. One reason is one fewer library to depend on and they are much faster than the jQuery equivalents.
One fantastic reference for jQuery equivalents is http://youmightnotneedjquery.com/.
As far as your question is concerned, I took the below code from the above link :)
Only caveat is it only works with Internet Explorer 9 and later.
function ready(fn) {
if (document.readyState != 'loading') {
fn();
}
else {
document.addEventListener('DOMContentLoaded', fn);
}
}
This cross-browser code will call a function once the DOM is ready:
var domReady=function(func){
var scriptText='('+func+')();';
var scriptElement=document.createElement('script');
scriptElement.innerText=scriptText;
document.body.appendChild(scriptElement);
};
Here's how it works:
The first line of domReady calls the toString method of the function to get a string representation of the function you pass in and wraps it in an expression that immediately calls the function.
The rest of domReady creates a script element with the expression and appends it to the body of the document.
The browser runs script tags appended to body after the DOM is ready.
For example, if you do this: domReady(function(){alert();});, the following will appended to the body element:
<script>(function (){alert();})();</script>
Note that this works only for user-defined functions. The following won't work: domReady(alert);
How about this solution?
// other onload attached earlier
window.onload=function() {
alert('test');
};
tmpPreviousFunction=window.onload ? window.onload : null;
// our onload function
window.onload=function() {
alert('another message');
// execute previous one
if (tmpPreviousFunction) tmpPreviousFunction();
};
We found a quick-and-dirty cross browser implementation of ours that may do the trick for most simple cases with a minimal implementation:
window.onReady = function onReady(fn){
document.body ? fn() : setTimeout(function(){ onReady(fn);},50);
};
I simply use:
setTimeout(function(){
//reference/manipulate DOM here
});
And unlike document.addEventListener("DOMContentLoaded" //etc as in the very top answer, it works as far back as IE9 -- http://caniuse.com/#search=DOMContentLoaded only indicates as recently as IE11.
Interestingly I stumbled upon this setTimeout solution in 2009: Is checking for the readiness of the DOM overkill?, which probably could have been worded slightly better, as I meant "is it overkill to use various frameworks' more complicated approaches to check for the readiness of the DOM".
My best explanation for why this technique works is that, when the script with such a setTimeout has been reached, the DOM is in the middle of being parsed, so execution of the code within the setTimeout gets deferred until that operation is finished.
Comparison
Here (in below snippet) is comparison of chosen available browser "built-in" methods and their execution sequence. Remarks
the document.onload (X) is not supported by any modern browser (event is never fired)
if you use <body onload="bodyOnLoad()"> (F) and at the same time window.onload (E) then only first one will be executed (because it override second one)
event handler given in <body onload="..."> (F) is wrapped by additional onload function
document.onreadystatechange (D) not override document .addEventListener('readystatechange'...) (C) probably cecasue onXYZevent-like methods are independent than addEventListener queues (which allows add multiple listeners). Probably nothing happens between execution this two handlers.
all scripts write their timestamp in console - but scripts which also have access to div write their timestamps also in body (click "Full Page" link after script execution to see it).
solutions readystatechange (C,D) are executed multiple times by browser but for different document states:
loading - the document is loading (no fired in snippet)
interactive - the document is parsed, fired before DOMContentLoaded
complete - the document and resources are loaded, fired before body/window onload
<html>
<head>
<script>
// solution A
console.log(`[timestamp: ${Date.now()}] A: Head script`) ;
// solution B
document.addEventListener("DOMContentLoaded", () => {
print(`[timestamp: ${Date.now()}] B: DOMContentLoaded`);
});
// solution C
document.addEventListener('readystatechange', () => {
print(`[timestamp: ${Date.now()}] C: ReadyState: ${document.readyState}`);
});
// solution D
document.onreadystatechange = s=> {print(`[timestamp: ${Date.now()}] D: document.onreadystatechange ReadyState: ${document.readyState}`)};
// solution E (never executed)
window.onload = () => {
print(`E: <body onload="..."> override this handler`);
};
// solution F
function bodyOnLoad() {
print(`[timestamp: ${Date.now()}] F: <body onload='...'>`);
infoAboutOnLoad(); // additional info
}
// solution X
document.onload = () => {print(`document.onload is never fired`)};
// HELPERS
function print(txt) {
console.log(txt);
if(mydiv) mydiv.innerHTML += txt.replace('<','<').replace('>','>') + '<br>';
}
function infoAboutOnLoad() {
console.log("window.onload (after override):", (''+document.body.onload).replace(/\s+/g,' '));
console.log(`body.onload==window.onload --> ${document.body.onload==window.onload}`);
}
console.log("window.onload (before override):", (''+document.body.onload).replace(/\s+/g,' '));
</script>
</head>
<body onload="bodyOnLoad()">
<div id="mydiv"></div>
<!-- this script must te at the bottom of <body> -->
<script>
// solution G
print(`[timestamp: ${Date.now()}] G: <body> bottom script`);
</script>
</body>
</html>
Nowadays you should use modules. Put your code into the default function of a module and import the function into a script element.
client.js:
export default function ()
{
alert ("test");
}
index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>test</title>
</head>
<body>
<script type="module">
import main from './client.js';
main ();
</script>
</body>
</html>
Here's what I use, it's fast and covers all bases I think; works for everything except IE<9.
(() => { function fn() {
// "On document ready" commands:
console.log(document.readyState);
};
if (document.readyState != 'loading') {fn()}
else {document.addEventListener('DOMContentLoaded', fn)}
})();
This seems to catch all cases:
fires immediately if the DOM is already ready (if the DOM is not "loading", but either "interactive" or "complete")
if the DOM is still loading, it sets up an event listener for when the DOM
is available (interactive).
The DOMContentLoaded event is available in IE9 and everything else, so I personally think it's OK to use this. Rewrite the arrow function declaration to a regular anonymous function if you're not transpiling your code from ES2015 to ES5.
If you want to wait until all assets are loaded, all images displayed etc then use window.onload instead.
If you don't have to support very old browsers, here is a way to do it even when your external script is loaded with async attribute:
HTMLDocument.prototype.ready = new Promise(function(resolve) {
if(document.readyState != "loading")
resolve();
else
document.addEventListener("DOMContentLoaded", function() {
resolve();
});
});
document.ready.then(function() {
console.log("document.ready");
});
For IE9+:
function ready(fn) {
if (document.readyState != 'loading'){
fn();
} else {
document.addEventListener('DOMContentLoaded', fn);
}
}
The setTimeout/setInterval solutions presented here will only work in specific circumstances.
The problem shows up especially in older Internet Explorer versions up to 8.
The variables affecting the success of these setTimeout/setInterval solutions are:
1) dynamic or static HTML
2) cached or non cached requests
3) size of the complete HTML document
4) chunked or non chunked transfer encoding
the original (native Javascript) code solving this specific issue is here:
https://github.com/dperini/ContentLoaded
http://javascript.nwbox.com/ContentLoaded (test)
this is the code from which the jQuery team have built their implementation.
If you are loading jQuery near the bottom of BODY, but are having trouble with code that writes out jQuery(<func>) or jQuery(document).ready(<func>), check out jqShim on Github.
Rather than recreate its own document ready function, it simply holds onto the functions until jQuery is available then proceeds with jQuery as expected. The point of moving jQuery to the bottom of body is to speed up page load, and you can still accomplish it by inlining the jqShim.min.js in the head of your template.
I ended up writing this code to make moving all the scripts in WordPress to the footer, and just this shim code now sits directly in the header.
Related
I have a script that uses $(document).ready, but it doesn't use anything else from jQuery. I'd like to lighten it up by removing the jQuery dependency.
How can I implement my own $(document).ready functionality without using jQuery? I know that using window.onload will not be the same, as window.onload fires after all images, frames, etc. have been loaded.
There is a standards based replacement,DOMContentLoaded that is supported by over 99% of browsers, though not IE8:
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 );
}
Edit:
2023 update, use this:
function ready(fn) {
if (document.readyState !== 'loading') {
fn();
return;
}
document.addEventListener('DOMContentLoaded', fn);
}
From: https://youmightnotneedjquery.com/
Here is a viable replacement for jQuery ready
function ready(callback){
// in case the document is already rendered
if (document.readyState!='loading') callback();
// modern browsers
else if (document.addEventListener) document.addEventListener('DOMContentLoaded', callback);
// IE <= 8
else document.attachEvent('onreadystatechange', function(){
if (document.readyState=='complete') callback();
});
}
ready(function(){
// do something
});
Taken from
https://plainjs.com/javascript/events/running-code-when-the-document-is-ready-15/
Another good domReady function here taken from https://stackoverflow.com/a/9899701/175071
As the accepted answer was very far from complete, I stitched together a "ready" function like jQuery.ready() based on jQuery 1.6.2 source:
var ready = (function(){
var readyList,
DOMContentLoaded,
class2type = {};
class2type["[object Boolean]"] = "boolean";
class2type["[object Number]"] = "number";
class2type["[object String]"] = "string";
class2type["[object Function]"] = "function";
class2type["[object Array]"] = "array";
class2type["[object Date]"] = "date";
class2type["[object RegExp]"] = "regexp";
class2type["[object Object]"] = "object";
var ReadyObj = {
// Is the DOM ready to be used? Set to true once it occurs.
isReady: false,
// A counter to track how many items to wait for before
// the ready event fires. See #6781
readyWait: 1,
// Hold (or release) the ready event
holdReady: function( hold ) {
if ( hold ) {
ReadyObj.readyWait++;
} else {
ReadyObj.ready( true );
}
},
// Handle when the DOM is ready
ready: function( wait ) {
// Either a released hold or an DOMready/load event and not yet ready
if ( (wait === true && !--ReadyObj.readyWait) || (wait !== true && !ReadyObj.isReady) ) {
// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
if ( !document.body ) {
return setTimeout( ReadyObj.ready, 1 );
}
// Remember that the DOM is ready
ReadyObj.isReady = true;
// If a normal DOM Ready event fired, decrement, and wait if need be
if ( wait !== true && --ReadyObj.readyWait > 0 ) {
return;
}
// If there are functions bound, to execute
readyList.resolveWith( document, [ ReadyObj ] );
// Trigger any bound ready events
//if ( ReadyObj.fn.trigger ) {
// ReadyObj( document ).trigger( "ready" ).unbind( "ready" );
//}
}
},
bindReady: function() {
if ( readyList ) {
return;
}
readyList = ReadyObj._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( ReadyObj.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", ReadyObj.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", ReadyObj.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();
}
}
},
_Deferred: function() {
var // callbacks list
callbacks = [],
// stored [ context , args ]
fired,
// to avoid firing when already doing so
firing,
// flag to know if the deferred has been cancelled
cancelled,
// the deferred itself
deferred = {
// done( f1, f2, ...)
done: function() {
if ( !cancelled ) {
var args = arguments,
i,
length,
elem,
type,
_fired;
if ( fired ) {
_fired = fired;
fired = 0;
}
for ( i = 0, length = args.length; i < length; i++ ) {
elem = args[ i ];
type = ReadyObj.type( elem );
if ( type === "array" ) {
deferred.done.apply( deferred, elem );
} else if ( type === "function" ) {
callbacks.push( elem );
}
}
if ( _fired ) {
deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );
}
}
return this;
},
// resolve with given context and args
resolveWith: function( context, args ) {
if ( !cancelled && !fired && !firing ) {
// make sure args are available (#8421)
args = args || [];
firing = 1;
try {
while( callbacks[ 0 ] ) {
callbacks.shift().apply( context, args );//shifts a callback, and applies it to document
}
}
finally {
fired = [ context, args ];
firing = 0;
}
}
return this;
},
// resolve with this as context and given arguments
resolve: function() {
deferred.resolveWith( this, arguments );
return this;
},
// Has this deferred been resolved?
isResolved: function() {
return !!( firing || fired );
},
// Cancel
cancel: function() {
cancelled = 1;
callbacks = [];
return this;
}
};
return deferred;
},
type: function( obj ) {
return obj == null ?
String( obj ) :
class2type[ Object.prototype.toString.call(obj) ] || "object";
}
}
// The DOM ready check for Internet Explorer
function doScrollCheck() {
if ( ReadyObj.isReady ) {
return;
}
try {
// If IE is used, use the trick by Diego Perini
// http://javascript.nwbox.com/IEContentLoaded/
document.documentElement.doScroll("left");
} catch(e) {
setTimeout( doScrollCheck, 1 );
return;
}
// and execute any waiting functions
ReadyObj.ready();
}
// Cleanup functions for the document ready method
if ( document.addEventListener ) {
DOMContentLoaded = function() {
document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
ReadyObj.ready();
};
} else if ( document.attachEvent ) {
DOMContentLoaded = function() {
// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
if ( document.readyState === "complete" ) {
document.detachEvent( "onreadystatechange", DOMContentLoaded );
ReadyObj.ready();
}
};
}
function ready( fn ) {
// Attach the listeners
ReadyObj.bindReady();
var type = ReadyObj.type( fn );
// Add the callback
readyList.done( fn );//readyList is result of _Deferred()
}
return ready;
})();
How to use:
<script>
ready(function(){
alert('It works!');
});
ready(function(){
alert('Also works!');
});
</script>
I am not sure how functional this code is, but it worked fine with my superficial tests. This took quite a while, so I hope you and others can benefit from it.
PS.: I suggest compiling it.
Or you can use http://dustindiaz.com/smallest-domready-ever:
function r(f){/in/.test(document.readyState)?setTimeout(r,9,f):f()}
r(function(){/*code to run*/});
or the native function if you only need to support the new browsers (Unlike jQuery ready, this won't run if you add this after the page has loaded)
document.addEventListener('DOMContentLoaded',function(){/*fun code to run*/})
Three options:
If script is the last tag of the body, the DOM would be ready before script tag executes
When the DOM is ready, "readyState" will change to "complete"
Put everything under 'DOMContentLoaded' event listener
onreadystatechange
document.onreadystatechange = function () {
if (document.readyState == "complete") {
// document is ready. Do your stuff here
}
}
Source: MDN
DOMContentLoaded
document.addEventListener('DOMContentLoaded', function() {
console.log('document is ready. I can sleep now');
});
Concerned about stone age browsers:
Go to the jQuery source code and use the ready function. In that case you are not parsing+executing the whole library you're are doing only a very small part of it.
Place your <script>/*JavaScript code*/</script> right before the closing </body> tag.
Admittedly, this might not suit everyone's purposes since it requires changing the HTML file rather than just doing something in the JavaScript file a la document.ready, but still...
Poor man's solution:
var checkLoad = function() {
document.readyState !== "complete" ? setTimeout(checkLoad, 11) : alert("loaded!");
};
checkLoad();
View Fiddle
Added this one, a bit better I guess, own scope, and non recursive
(function(){
var tId = setInterval(function() {
if (document.readyState == "complete") onComplete()
}, 11);
function onComplete(){
clearInterval(tId);
alert("loaded!");
};
})()
View Fiddle
I use this:
document.addEventListener("DOMContentLoaded", function(event) {
//Do work
});
Note: This probably only works with newer browsers, especially these: http://caniuse.com/#feat=domcontentloaded
It is year 2020 and <script> tag has defer attribute.
for example:
<script src="demo_defer.js" defer></script>
it specifies that the script is executed when the page has finished parsing.
https://www.w3schools.com/tags/att_script_defer.asp
2022 version
In 2022, all you need to do is put the defer attribute on your script, and load it in the head!
Reference: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-defer
<!doctype html>
<html>
<head>
<script src="/script.js" defer></script>
</head>
<body>
<p>In 2022, all you need to do is put the defer attribute on your script, and load it in the head!</p>
</body>
</html>
This question was asked quite a long time ago. For anyone just seeing this question, there is now a site called "you might not need jquery" which breaks down - by level of IE support required - all the functionality of jquery and provides some alternative, smaller libraries.
IE8 document ready script according to you might not need jquery
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();
});
}
Really, if you care about Internet Explorer 9+ only, this code would be enough to replace jQuery.ready:
document.addEventListener("DOMContentLoaded", callback);
If you worry about Internet Explorer 6 and some really strange and rare browsers, this will work:
domReady: function (callback) {
// Mozilla, Opera and WebKit
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", callback, false);
// If Internet Explorer, the event model is used
} else if (document.attachEvent) {
document.attachEvent("onreadystatechange", function() {
if (document.readyState === "complete" ) {
callback();
}
});
// A fallback to window.onload, that will always work
} else {
var oldOnload = window.onload;
window.onload = function () {
oldOnload && oldOnload();
callback();
}
}
},
Cross-browser (old browsers too) and a simple solution:
var docLoaded = setInterval(function () {
if(document.readyState !== "complete") return;
clearInterval(docLoaded);
/*
Your code goes here i.e. init()
*/
}, 30);
Showing alert in jsfiddle
I was recently using this for a mobile site. This is John Resig's simplified version from "Pro JavaScript Techniques". It depends on addEvent.
var ready = ( function () {
function ready( f ) {
if( ready.done ) return f();
if( ready.timer ) {
ready.ready.push(f);
} else {
addEvent( window, "load", isDOMReady );
ready.ready = [ f ];
ready.timer = setInterval(isDOMReady, 13);
}
};
function isDOMReady() {
if( ready.done ) return false;
if( document && document.getElementsByTagName && document.getElementById && document.body ) {
clearInterval( ready.timer );
ready.timer = null;
for( var i = 0; i < ready.ready.length; i++ ) {
ready.ready[i]();
}
ready.ready = null;
ready.done = true;
}
}
return ready;
})();
The jQuery answer was pretty useful to me. With a little refactory it fitted my needs well.
I hope it helps anybody else.
function onReady ( callback ){
var addListener = document.addEventListener || document.attachEvent,
removeListener = document.removeEventListener || document.detachEvent
eventName = document.addEventListener ? "DOMContentLoaded" : "onreadystatechange"
addListener.call(document, eventName, function(){
removeListener( eventName, arguments.callee, false )
callback()
}, false )
}
Here is the smallest code snippet to test DOM ready which works across all browsers (even IE 8):
r(function(){
alert('DOM Ready!');
});
function r(f){/in/.test(document.readyState)?setTimeout('r('+f+')',9):f()}
See this answer.
Just add this to the bottom of your HTML page...
<script>
Your_Function();
</script>
Because, HTML documents are parsed by top-bottom.
Most minimal and 100% working
I have picked the answer from PlainJS and it's working fine for me. It extends DOMContentLoaded so that it can be accepted at all the browsers.
This function is the equivalent of jQuery's $(document).ready() method:
document.addEventListener('DOMContentLoaded', function(){
// do something
});
However, in contrast to jQuery, this code will only run properly in modern browsers (IE > 8) and it won't in case the document is already rendered at the time this script gets inserted (e.g. via Ajax). Therefore, we need to extend this a little bit:
function run() {
// do something
}
// in case the document is already rendered
if (document.readyState!='loading') run();
// modern browsers
else if (document.addEventListener)
document.addEventListener('DOMContentLoaded', run);
// IE <= 8
else document.attachEvent('onreadystatechange', function(){
if (document.readyState=='complete') run();
});
This covers basically all possibilities and is a viable replacement for the jQuery helper.
Simplest way using pure JavaScript. Without jQuery:
document.addEventListener("DOMContentLoaded", function(event) {
// Your code to run since DOM is loaded and ready
});
It is worth looking in Rock Solid addEvent() and http://www.braksator.com/how-to-make-your-own-jquery.
Here is the code in case the site goes down
function addEvent(obj, type, fn) {
if (obj.addEventListener) {
obj.addEventListener(type, fn, false);
EventCache.add(obj, type, fn);
}
else if (obj.attachEvent) {
obj["e"+type+fn] = fn;
obj[type+fn] = function() { obj["e"+type+fn]( window.event ); }
obj.attachEvent( "on"+type, obj[type+fn] );
EventCache.add(obj, type, fn);
}
else {
obj["on"+type] = obj["e"+type+fn];
}
}
var EventCache = function(){
var listEvents = [];
return {
listEvents : listEvents,
add : function(node, sEventName, fHandler){
listEvents.push(arguments);
},
flush : function(){
var i, item;
for(i = listEvents.length - 1; i >= 0; i = i - 1){
item = listEvents[i];
if(item[0].removeEventListener){
item[0].removeEventListener(item[1], item[2], item[3]);
};
if(item[1].substring(0, 2) != "on"){
item[1] = "on" + item[1];
};
if(item[0].detachEvent){
item[0].detachEvent(item[1], item[2]);
};
item[0][item[1]] = null;
};
}
};
}();
// Usage
addEvent(window, 'unload', EventCache.flush);
addEvent(window, 'load', function(){alert("I'm ready");});
It's always good to use JavaScript equivalents as compared to jQuery. One reason is one fewer library to depend on and they are much faster than the jQuery equivalents.
One fantastic reference for jQuery equivalents is http://youmightnotneedjquery.com/.
As far as your question is concerned, I took the below code from the above link :)
Only caveat is it only works with Internet Explorer 9 and later.
function ready(fn) {
if (document.readyState != 'loading') {
fn();
}
else {
document.addEventListener('DOMContentLoaded', fn);
}
}
This cross-browser code will call a function once the DOM is ready:
var domReady=function(func){
var scriptText='('+func+')();';
var scriptElement=document.createElement('script');
scriptElement.innerText=scriptText;
document.body.appendChild(scriptElement);
};
Here's how it works:
The first line of domReady calls the toString method of the function to get a string representation of the function you pass in and wraps it in an expression that immediately calls the function.
The rest of domReady creates a script element with the expression and appends it to the body of the document.
The browser runs script tags appended to body after the DOM is ready.
For example, if you do this: domReady(function(){alert();});, the following will appended to the body element:
<script>(function (){alert();})();</script>
Note that this works only for user-defined functions. The following won't work: domReady(alert);
How about this solution?
// other onload attached earlier
window.onload=function() {
alert('test');
};
tmpPreviousFunction=window.onload ? window.onload : null;
// our onload function
window.onload=function() {
alert('another message');
// execute previous one
if (tmpPreviousFunction) tmpPreviousFunction();
};
We found a quick-and-dirty cross browser implementation of ours that may do the trick for most simple cases with a minimal implementation:
window.onReady = function onReady(fn){
document.body ? fn() : setTimeout(function(){ onReady(fn);},50);
};
I simply use:
setTimeout(function(){
//reference/manipulate DOM here
});
And unlike document.addEventListener("DOMContentLoaded" //etc as in the very top answer, it works as far back as IE9 -- http://caniuse.com/#search=DOMContentLoaded only indicates as recently as IE11.
Interestingly I stumbled upon this setTimeout solution in 2009: Is checking for the readiness of the DOM overkill?, which probably could have been worded slightly better, as I meant "is it overkill to use various frameworks' more complicated approaches to check for the readiness of the DOM".
My best explanation for why this technique works is that, when the script with such a setTimeout has been reached, the DOM is in the middle of being parsed, so execution of the code within the setTimeout gets deferred until that operation is finished.
Comparison
Here (in below snippet) is comparison of chosen available browser "built-in" methods and their execution sequence. Remarks
the document.onload (X) is not supported by any modern browser (event is never fired)
if you use <body onload="bodyOnLoad()"> (F) and at the same time window.onload (E) then only first one will be executed (because it override second one)
event handler given in <body onload="..."> (F) is wrapped by additional onload function
document.onreadystatechange (D) not override document .addEventListener('readystatechange'...) (C) probably cecasue onXYZevent-like methods are independent than addEventListener queues (which allows add multiple listeners). Probably nothing happens between execution this two handlers.
all scripts write their timestamp in console - but scripts which also have access to div write their timestamps also in body (click "Full Page" link after script execution to see it).
solutions readystatechange (C,D) are executed multiple times by browser but for different document states:
loading - the document is loading (no fired in snippet)
interactive - the document is parsed, fired before DOMContentLoaded
complete - the document and resources are loaded, fired before body/window onload
<html>
<head>
<script>
// solution A
console.log(`[timestamp: ${Date.now()}] A: Head script`) ;
// solution B
document.addEventListener("DOMContentLoaded", () => {
print(`[timestamp: ${Date.now()}] B: DOMContentLoaded`);
});
// solution C
document.addEventListener('readystatechange', () => {
print(`[timestamp: ${Date.now()}] C: ReadyState: ${document.readyState}`);
});
// solution D
document.onreadystatechange = s=> {print(`[timestamp: ${Date.now()}] D: document.onreadystatechange ReadyState: ${document.readyState}`)};
// solution E (never executed)
window.onload = () => {
print(`E: <body onload="..."> override this handler`);
};
// solution F
function bodyOnLoad() {
print(`[timestamp: ${Date.now()}] F: <body onload='...'>`);
infoAboutOnLoad(); // additional info
}
// solution X
document.onload = () => {print(`document.onload is never fired`)};
// HELPERS
function print(txt) {
console.log(txt);
if(mydiv) mydiv.innerHTML += txt.replace('<','<').replace('>','>') + '<br>';
}
function infoAboutOnLoad() {
console.log("window.onload (after override):", (''+document.body.onload).replace(/\s+/g,' '));
console.log(`body.onload==window.onload --> ${document.body.onload==window.onload}`);
}
console.log("window.onload (before override):", (''+document.body.onload).replace(/\s+/g,' '));
</script>
</head>
<body onload="bodyOnLoad()">
<div id="mydiv"></div>
<!-- this script must te at the bottom of <body> -->
<script>
// solution G
print(`[timestamp: ${Date.now()}] G: <body> bottom script`);
</script>
</body>
</html>
Nowadays you should use modules. Put your code into the default function of a module and import the function into a script element.
client.js:
export default function ()
{
alert ("test");
}
index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>test</title>
</head>
<body>
<script type="module">
import main from './client.js';
main ();
</script>
</body>
</html>
Here's what I use, it's fast and covers all bases I think; works for everything except IE<9.
(() => { function fn() {
// "On document ready" commands:
console.log(document.readyState);
};
if (document.readyState != 'loading') {fn()}
else {document.addEventListener('DOMContentLoaded', fn)}
})();
This seems to catch all cases:
fires immediately if the DOM is already ready (if the DOM is not "loading", but either "interactive" or "complete")
if the DOM is still loading, it sets up an event listener for when the DOM
is available (interactive).
The DOMContentLoaded event is available in IE9 and everything else, so I personally think it's OK to use this. Rewrite the arrow function declaration to a regular anonymous function if you're not transpiling your code from ES2015 to ES5.
If you want to wait until all assets are loaded, all images displayed etc then use window.onload instead.
If you don't have to support very old browsers, here is a way to do it even when your external script is loaded with async attribute:
HTMLDocument.prototype.ready = new Promise(function(resolve) {
if(document.readyState != "loading")
resolve();
else
document.addEventListener("DOMContentLoaded", function() {
resolve();
});
});
document.ready.then(function() {
console.log("document.ready");
});
For IE9+:
function ready(fn) {
if (document.readyState != 'loading'){
fn();
} else {
document.addEventListener('DOMContentLoaded', fn);
}
}
The setTimeout/setInterval solutions presented here will only work in specific circumstances.
The problem shows up especially in older Internet Explorer versions up to 8.
The variables affecting the success of these setTimeout/setInterval solutions are:
1) dynamic or static HTML
2) cached or non cached requests
3) size of the complete HTML document
4) chunked or non chunked transfer encoding
the original (native Javascript) code solving this specific issue is here:
https://github.com/dperini/ContentLoaded
http://javascript.nwbox.com/ContentLoaded (test)
this is the code from which the jQuery team have built their implementation.
If you are loading jQuery near the bottom of BODY, but are having trouble with code that writes out jQuery(<func>) or jQuery(document).ready(<func>), check out jqShim on Github.
Rather than recreate its own document ready function, it simply holds onto the functions until jQuery is available then proceeds with jQuery as expected. The point of moving jQuery to the bottom of body is to speed up page load, and you can still accomplish it by inlining the jqShim.min.js in the head of your template.
I ended up writing this code to make moving all the scripts in WordPress to the footer, and just this shim code now sits directly in the header.
I have a script that uses $(document).ready, but it doesn't use anything else from jQuery. I'd like to lighten it up by removing the jQuery dependency.
How can I implement my own $(document).ready functionality without using jQuery? I know that using window.onload will not be the same, as window.onload fires after all images, frames, etc. have been loaded.
There is a standards based replacement,DOMContentLoaded that is supported by over 99% of browsers, though not IE8:
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 );
}
Edit:
2023 update, use this:
function ready(fn) {
if (document.readyState !== 'loading') {
fn();
return;
}
document.addEventListener('DOMContentLoaded', fn);
}
From: https://youmightnotneedjquery.com/
Here is a viable replacement for jQuery ready
function ready(callback){
// in case the document is already rendered
if (document.readyState!='loading') callback();
// modern browsers
else if (document.addEventListener) document.addEventListener('DOMContentLoaded', callback);
// IE <= 8
else document.attachEvent('onreadystatechange', function(){
if (document.readyState=='complete') callback();
});
}
ready(function(){
// do something
});
Taken from
https://plainjs.com/javascript/events/running-code-when-the-document-is-ready-15/
Another good domReady function here taken from https://stackoverflow.com/a/9899701/175071
As the accepted answer was very far from complete, I stitched together a "ready" function like jQuery.ready() based on jQuery 1.6.2 source:
var ready = (function(){
var readyList,
DOMContentLoaded,
class2type = {};
class2type["[object Boolean]"] = "boolean";
class2type["[object Number]"] = "number";
class2type["[object String]"] = "string";
class2type["[object Function]"] = "function";
class2type["[object Array]"] = "array";
class2type["[object Date]"] = "date";
class2type["[object RegExp]"] = "regexp";
class2type["[object Object]"] = "object";
var ReadyObj = {
// Is the DOM ready to be used? Set to true once it occurs.
isReady: false,
// A counter to track how many items to wait for before
// the ready event fires. See #6781
readyWait: 1,
// Hold (or release) the ready event
holdReady: function( hold ) {
if ( hold ) {
ReadyObj.readyWait++;
} else {
ReadyObj.ready( true );
}
},
// Handle when the DOM is ready
ready: function( wait ) {
// Either a released hold or an DOMready/load event and not yet ready
if ( (wait === true && !--ReadyObj.readyWait) || (wait !== true && !ReadyObj.isReady) ) {
// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
if ( !document.body ) {
return setTimeout( ReadyObj.ready, 1 );
}
// Remember that the DOM is ready
ReadyObj.isReady = true;
// If a normal DOM Ready event fired, decrement, and wait if need be
if ( wait !== true && --ReadyObj.readyWait > 0 ) {
return;
}
// If there are functions bound, to execute
readyList.resolveWith( document, [ ReadyObj ] );
// Trigger any bound ready events
//if ( ReadyObj.fn.trigger ) {
// ReadyObj( document ).trigger( "ready" ).unbind( "ready" );
//}
}
},
bindReady: function() {
if ( readyList ) {
return;
}
readyList = ReadyObj._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( ReadyObj.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", ReadyObj.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", ReadyObj.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();
}
}
},
_Deferred: function() {
var // callbacks list
callbacks = [],
// stored [ context , args ]
fired,
// to avoid firing when already doing so
firing,
// flag to know if the deferred has been cancelled
cancelled,
// the deferred itself
deferred = {
// done( f1, f2, ...)
done: function() {
if ( !cancelled ) {
var args = arguments,
i,
length,
elem,
type,
_fired;
if ( fired ) {
_fired = fired;
fired = 0;
}
for ( i = 0, length = args.length; i < length; i++ ) {
elem = args[ i ];
type = ReadyObj.type( elem );
if ( type === "array" ) {
deferred.done.apply( deferred, elem );
} else if ( type === "function" ) {
callbacks.push( elem );
}
}
if ( _fired ) {
deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );
}
}
return this;
},
// resolve with given context and args
resolveWith: function( context, args ) {
if ( !cancelled && !fired && !firing ) {
// make sure args are available (#8421)
args = args || [];
firing = 1;
try {
while( callbacks[ 0 ] ) {
callbacks.shift().apply( context, args );//shifts a callback, and applies it to document
}
}
finally {
fired = [ context, args ];
firing = 0;
}
}
return this;
},
// resolve with this as context and given arguments
resolve: function() {
deferred.resolveWith( this, arguments );
return this;
},
// Has this deferred been resolved?
isResolved: function() {
return !!( firing || fired );
},
// Cancel
cancel: function() {
cancelled = 1;
callbacks = [];
return this;
}
};
return deferred;
},
type: function( obj ) {
return obj == null ?
String( obj ) :
class2type[ Object.prototype.toString.call(obj) ] || "object";
}
}
// The DOM ready check for Internet Explorer
function doScrollCheck() {
if ( ReadyObj.isReady ) {
return;
}
try {
// If IE is used, use the trick by Diego Perini
// http://javascript.nwbox.com/IEContentLoaded/
document.documentElement.doScroll("left");
} catch(e) {
setTimeout( doScrollCheck, 1 );
return;
}
// and execute any waiting functions
ReadyObj.ready();
}
// Cleanup functions for the document ready method
if ( document.addEventListener ) {
DOMContentLoaded = function() {
document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
ReadyObj.ready();
};
} else if ( document.attachEvent ) {
DOMContentLoaded = function() {
// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
if ( document.readyState === "complete" ) {
document.detachEvent( "onreadystatechange", DOMContentLoaded );
ReadyObj.ready();
}
};
}
function ready( fn ) {
// Attach the listeners
ReadyObj.bindReady();
var type = ReadyObj.type( fn );
// Add the callback
readyList.done( fn );//readyList is result of _Deferred()
}
return ready;
})();
How to use:
<script>
ready(function(){
alert('It works!');
});
ready(function(){
alert('Also works!');
});
</script>
I am not sure how functional this code is, but it worked fine with my superficial tests. This took quite a while, so I hope you and others can benefit from it.
PS.: I suggest compiling it.
Or you can use http://dustindiaz.com/smallest-domready-ever:
function r(f){/in/.test(document.readyState)?setTimeout(r,9,f):f()}
r(function(){/*code to run*/});
or the native function if you only need to support the new browsers (Unlike jQuery ready, this won't run if you add this after the page has loaded)
document.addEventListener('DOMContentLoaded',function(){/*fun code to run*/})
Three options:
If script is the last tag of the body, the DOM would be ready before script tag executes
When the DOM is ready, "readyState" will change to "complete"
Put everything under 'DOMContentLoaded' event listener
onreadystatechange
document.onreadystatechange = function () {
if (document.readyState == "complete") {
// document is ready. Do your stuff here
}
}
Source: MDN
DOMContentLoaded
document.addEventListener('DOMContentLoaded', function() {
console.log('document is ready. I can sleep now');
});
Concerned about stone age browsers:
Go to the jQuery source code and use the ready function. In that case you are not parsing+executing the whole library you're are doing only a very small part of it.
Place your <script>/*JavaScript code*/</script> right before the closing </body> tag.
Admittedly, this might not suit everyone's purposes since it requires changing the HTML file rather than just doing something in the JavaScript file a la document.ready, but still...
Poor man's solution:
var checkLoad = function() {
document.readyState !== "complete" ? setTimeout(checkLoad, 11) : alert("loaded!");
};
checkLoad();
View Fiddle
Added this one, a bit better I guess, own scope, and non recursive
(function(){
var tId = setInterval(function() {
if (document.readyState == "complete") onComplete()
}, 11);
function onComplete(){
clearInterval(tId);
alert("loaded!");
};
})()
View Fiddle
I use this:
document.addEventListener("DOMContentLoaded", function(event) {
//Do work
});
Note: This probably only works with newer browsers, especially these: http://caniuse.com/#feat=domcontentloaded
It is year 2020 and <script> tag has defer attribute.
for example:
<script src="demo_defer.js" defer></script>
it specifies that the script is executed when the page has finished parsing.
https://www.w3schools.com/tags/att_script_defer.asp
2022 version
In 2022, all you need to do is put the defer attribute on your script, and load it in the head!
Reference: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-defer
<!doctype html>
<html>
<head>
<script src="/script.js" defer></script>
</head>
<body>
<p>In 2022, all you need to do is put the defer attribute on your script, and load it in the head!</p>
</body>
</html>
This question was asked quite a long time ago. For anyone just seeing this question, there is now a site called "you might not need jquery" which breaks down - by level of IE support required - all the functionality of jquery and provides some alternative, smaller libraries.
IE8 document ready script according to you might not need jquery
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();
});
}
Really, if you care about Internet Explorer 9+ only, this code would be enough to replace jQuery.ready:
document.addEventListener("DOMContentLoaded", callback);
If you worry about Internet Explorer 6 and some really strange and rare browsers, this will work:
domReady: function (callback) {
// Mozilla, Opera and WebKit
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", callback, false);
// If Internet Explorer, the event model is used
} else if (document.attachEvent) {
document.attachEvent("onreadystatechange", function() {
if (document.readyState === "complete" ) {
callback();
}
});
// A fallback to window.onload, that will always work
} else {
var oldOnload = window.onload;
window.onload = function () {
oldOnload && oldOnload();
callback();
}
}
},
Cross-browser (old browsers too) and a simple solution:
var docLoaded = setInterval(function () {
if(document.readyState !== "complete") return;
clearInterval(docLoaded);
/*
Your code goes here i.e. init()
*/
}, 30);
Showing alert in jsfiddle
I was recently using this for a mobile site. This is John Resig's simplified version from "Pro JavaScript Techniques". It depends on addEvent.
var ready = ( function () {
function ready( f ) {
if( ready.done ) return f();
if( ready.timer ) {
ready.ready.push(f);
} else {
addEvent( window, "load", isDOMReady );
ready.ready = [ f ];
ready.timer = setInterval(isDOMReady, 13);
}
};
function isDOMReady() {
if( ready.done ) return false;
if( document && document.getElementsByTagName && document.getElementById && document.body ) {
clearInterval( ready.timer );
ready.timer = null;
for( var i = 0; i < ready.ready.length; i++ ) {
ready.ready[i]();
}
ready.ready = null;
ready.done = true;
}
}
return ready;
})();
The jQuery answer was pretty useful to me. With a little refactory it fitted my needs well.
I hope it helps anybody else.
function onReady ( callback ){
var addListener = document.addEventListener || document.attachEvent,
removeListener = document.removeEventListener || document.detachEvent
eventName = document.addEventListener ? "DOMContentLoaded" : "onreadystatechange"
addListener.call(document, eventName, function(){
removeListener( eventName, arguments.callee, false )
callback()
}, false )
}
Here is the smallest code snippet to test DOM ready which works across all browsers (even IE 8):
r(function(){
alert('DOM Ready!');
});
function r(f){/in/.test(document.readyState)?setTimeout('r('+f+')',9):f()}
See this answer.
Just add this to the bottom of your HTML page...
<script>
Your_Function();
</script>
Because, HTML documents are parsed by top-bottom.
Most minimal and 100% working
I have picked the answer from PlainJS and it's working fine for me. It extends DOMContentLoaded so that it can be accepted at all the browsers.
This function is the equivalent of jQuery's $(document).ready() method:
document.addEventListener('DOMContentLoaded', function(){
// do something
});
However, in contrast to jQuery, this code will only run properly in modern browsers (IE > 8) and it won't in case the document is already rendered at the time this script gets inserted (e.g. via Ajax). Therefore, we need to extend this a little bit:
function run() {
// do something
}
// in case the document is already rendered
if (document.readyState!='loading') run();
// modern browsers
else if (document.addEventListener)
document.addEventListener('DOMContentLoaded', run);
// IE <= 8
else document.attachEvent('onreadystatechange', function(){
if (document.readyState=='complete') run();
});
This covers basically all possibilities and is a viable replacement for the jQuery helper.
Simplest way using pure JavaScript. Without jQuery:
document.addEventListener("DOMContentLoaded", function(event) {
// Your code to run since DOM is loaded and ready
});
It is worth looking in Rock Solid addEvent() and http://www.braksator.com/how-to-make-your-own-jquery.
Here is the code in case the site goes down
function addEvent(obj, type, fn) {
if (obj.addEventListener) {
obj.addEventListener(type, fn, false);
EventCache.add(obj, type, fn);
}
else if (obj.attachEvent) {
obj["e"+type+fn] = fn;
obj[type+fn] = function() { obj["e"+type+fn]( window.event ); }
obj.attachEvent( "on"+type, obj[type+fn] );
EventCache.add(obj, type, fn);
}
else {
obj["on"+type] = obj["e"+type+fn];
}
}
var EventCache = function(){
var listEvents = [];
return {
listEvents : listEvents,
add : function(node, sEventName, fHandler){
listEvents.push(arguments);
},
flush : function(){
var i, item;
for(i = listEvents.length - 1; i >= 0; i = i - 1){
item = listEvents[i];
if(item[0].removeEventListener){
item[0].removeEventListener(item[1], item[2], item[3]);
};
if(item[1].substring(0, 2) != "on"){
item[1] = "on" + item[1];
};
if(item[0].detachEvent){
item[0].detachEvent(item[1], item[2]);
};
item[0][item[1]] = null;
};
}
};
}();
// Usage
addEvent(window, 'unload', EventCache.flush);
addEvent(window, 'load', function(){alert("I'm ready");});
It's always good to use JavaScript equivalents as compared to jQuery. One reason is one fewer library to depend on and they are much faster than the jQuery equivalents.
One fantastic reference for jQuery equivalents is http://youmightnotneedjquery.com/.
As far as your question is concerned, I took the below code from the above link :)
Only caveat is it only works with Internet Explorer 9 and later.
function ready(fn) {
if (document.readyState != 'loading') {
fn();
}
else {
document.addEventListener('DOMContentLoaded', fn);
}
}
This cross-browser code will call a function once the DOM is ready:
var domReady=function(func){
var scriptText='('+func+')();';
var scriptElement=document.createElement('script');
scriptElement.innerText=scriptText;
document.body.appendChild(scriptElement);
};
Here's how it works:
The first line of domReady calls the toString method of the function to get a string representation of the function you pass in and wraps it in an expression that immediately calls the function.
The rest of domReady creates a script element with the expression and appends it to the body of the document.
The browser runs script tags appended to body after the DOM is ready.
For example, if you do this: domReady(function(){alert();});, the following will appended to the body element:
<script>(function (){alert();})();</script>
Note that this works only for user-defined functions. The following won't work: domReady(alert);
How about this solution?
// other onload attached earlier
window.onload=function() {
alert('test');
};
tmpPreviousFunction=window.onload ? window.onload : null;
// our onload function
window.onload=function() {
alert('another message');
// execute previous one
if (tmpPreviousFunction) tmpPreviousFunction();
};
We found a quick-and-dirty cross browser implementation of ours that may do the trick for most simple cases with a minimal implementation:
window.onReady = function onReady(fn){
document.body ? fn() : setTimeout(function(){ onReady(fn);},50);
};
I simply use:
setTimeout(function(){
//reference/manipulate DOM here
});
And unlike document.addEventListener("DOMContentLoaded" //etc as in the very top answer, it works as far back as IE9 -- http://caniuse.com/#search=DOMContentLoaded only indicates as recently as IE11.
Interestingly I stumbled upon this setTimeout solution in 2009: Is checking for the readiness of the DOM overkill?, which probably could have been worded slightly better, as I meant "is it overkill to use various frameworks' more complicated approaches to check for the readiness of the DOM".
My best explanation for why this technique works is that, when the script with such a setTimeout has been reached, the DOM is in the middle of being parsed, so execution of the code within the setTimeout gets deferred until that operation is finished.
Comparison
Here (in below snippet) is comparison of chosen available browser "built-in" methods and their execution sequence. Remarks
the document.onload (X) is not supported by any modern browser (event is never fired)
if you use <body onload="bodyOnLoad()"> (F) and at the same time window.onload (E) then only first one will be executed (because it override second one)
event handler given in <body onload="..."> (F) is wrapped by additional onload function
document.onreadystatechange (D) not override document .addEventListener('readystatechange'...) (C) probably cecasue onXYZevent-like methods are independent than addEventListener queues (which allows add multiple listeners). Probably nothing happens between execution this two handlers.
all scripts write their timestamp in console - but scripts which also have access to div write their timestamps also in body (click "Full Page" link after script execution to see it).
solutions readystatechange (C,D) are executed multiple times by browser but for different document states:
loading - the document is loading (no fired in snippet)
interactive - the document is parsed, fired before DOMContentLoaded
complete - the document and resources are loaded, fired before body/window onload
<html>
<head>
<script>
// solution A
console.log(`[timestamp: ${Date.now()}] A: Head script`) ;
// solution B
document.addEventListener("DOMContentLoaded", () => {
print(`[timestamp: ${Date.now()}] B: DOMContentLoaded`);
});
// solution C
document.addEventListener('readystatechange', () => {
print(`[timestamp: ${Date.now()}] C: ReadyState: ${document.readyState}`);
});
// solution D
document.onreadystatechange = s=> {print(`[timestamp: ${Date.now()}] D: document.onreadystatechange ReadyState: ${document.readyState}`)};
// solution E (never executed)
window.onload = () => {
print(`E: <body onload="..."> override this handler`);
};
// solution F
function bodyOnLoad() {
print(`[timestamp: ${Date.now()}] F: <body onload='...'>`);
infoAboutOnLoad(); // additional info
}
// solution X
document.onload = () => {print(`document.onload is never fired`)};
// HELPERS
function print(txt) {
console.log(txt);
if(mydiv) mydiv.innerHTML += txt.replace('<','<').replace('>','>') + '<br>';
}
function infoAboutOnLoad() {
console.log("window.onload (after override):", (''+document.body.onload).replace(/\s+/g,' '));
console.log(`body.onload==window.onload --> ${document.body.onload==window.onload}`);
}
console.log("window.onload (before override):", (''+document.body.onload).replace(/\s+/g,' '));
</script>
</head>
<body onload="bodyOnLoad()">
<div id="mydiv"></div>
<!-- this script must te at the bottom of <body> -->
<script>
// solution G
print(`[timestamp: ${Date.now()}] G: <body> bottom script`);
</script>
</body>
</html>
Nowadays you should use modules. Put your code into the default function of a module and import the function into a script element.
client.js:
export default function ()
{
alert ("test");
}
index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>test</title>
</head>
<body>
<script type="module">
import main from './client.js';
main ();
</script>
</body>
</html>
Here's what I use, it's fast and covers all bases I think; works for everything except IE<9.
(() => { function fn() {
// "On document ready" commands:
console.log(document.readyState);
};
if (document.readyState != 'loading') {fn()}
else {document.addEventListener('DOMContentLoaded', fn)}
})();
This seems to catch all cases:
fires immediately if the DOM is already ready (if the DOM is not "loading", but either "interactive" or "complete")
if the DOM is still loading, it sets up an event listener for when the DOM
is available (interactive).
The DOMContentLoaded event is available in IE9 and everything else, so I personally think it's OK to use this. Rewrite the arrow function declaration to a regular anonymous function if you're not transpiling your code from ES2015 to ES5.
If you want to wait until all assets are loaded, all images displayed etc then use window.onload instead.
If you don't have to support very old browsers, here is a way to do it even when your external script is loaded with async attribute:
HTMLDocument.prototype.ready = new Promise(function(resolve) {
if(document.readyState != "loading")
resolve();
else
document.addEventListener("DOMContentLoaded", function() {
resolve();
});
});
document.ready.then(function() {
console.log("document.ready");
});
For IE9+:
function ready(fn) {
if (document.readyState != 'loading'){
fn();
} else {
document.addEventListener('DOMContentLoaded', fn);
}
}
The setTimeout/setInterval solutions presented here will only work in specific circumstances.
The problem shows up especially in older Internet Explorer versions up to 8.
The variables affecting the success of these setTimeout/setInterval solutions are:
1) dynamic or static HTML
2) cached or non cached requests
3) size of the complete HTML document
4) chunked or non chunked transfer encoding
the original (native Javascript) code solving this specific issue is here:
https://github.com/dperini/ContentLoaded
http://javascript.nwbox.com/ContentLoaded (test)
this is the code from which the jQuery team have built their implementation.
If you are loading jQuery near the bottom of BODY, but are having trouble with code that writes out jQuery(<func>) or jQuery(document).ready(<func>), check out jqShim on Github.
Rather than recreate its own document ready function, it simply holds onto the functions until jQuery is available then proceeds with jQuery as expected. The point of moving jQuery to the bottom of body is to speed up page load, and you can still accomplish it by inlining the jqShim.min.js in the head of your template.
I ended up writing this code to make moving all the scripts in WordPress to the footer, and just this shim code now sits directly in the header.
I have a piece of JS code which needs to determine if DOM has loaded. I know there are several ways of executing JS code when DOM has loaded like:
$(document).ready(function() { ... }); // Jquery version
document.body.onload = function() { ... } // Vanila JS way
I am looking for some method which looks like
function isDOMLoaded() {
// Do something to check if DOM is loaded or not
// return true/false depending upon logic
}
PS: Update (Post Answer Accept)
I happen to see jquery also use the same approach to check if DOM has loaded. Take a look at the Implementation of jquery.ready() here
bindReady: function() {
if ( readyBound ) {
return;
}
readyBound = true;
// Catch cases where $(document).ready() is called after the
// browser event has already occurred.
if ( document.readyState === "complete" ) {
return jQuery.ready();
}
...
function isDOMLoaded(){
return document.readyState == 'complete';
}
You can use something like this
function isLoaded() {
return (document.readyState === 'ready' ||
document.readyState === 'complete')
}
Check for ready and complete status.
ready is only there for a short moment but do reflect when the DOM is ready. When the page is completely loaded however the status is changed to 'complete'. If you happen to check only for ready the function will fail, so we also check for this status.
How about this?
var flgDOMLoaded=false; //Set a global variable
$(document).ready(function() {
flgDOMLoaded= true;
// Some code
});
function isDOMLoaded() {
return flgDOMLoaded; // return it.
//You don't need this function at all. You could just access window.flgDOMLoaded
}
I'm using the popular addLoadEvent as follows for all my JS loading:
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
} else {
window.onload = function() {
if (oldonload) {
oldonload();
}
func();
}
}
}
addLoadEvent( locationToggle );
addLoadEvent( step1 );
addLoadEvent( step2 );
addLoadEvent( step3 );
addLoadEvent( getCounties );
addLoadEvent( mapSelection);
Everything I've read suggests this is a fairly bullet proof way of avoiding onload conflicts. And yet this method doesn't appear to working any better than wrapping the functions in an anonymous window.onload function. Both methods are causing identical onload conflicts with this set of functions.
I am loading these functions from within the same file as the addLoadEvent function itself. I'm also using calender.js which is a third party file which uses mootools 1.2.4 in an additional file. My files are otherwise free of Javascript.
First, could someone verify I've not damaged the code and I'm using it right. Second could someone suggest why the above is not resolving the conflicts?
edit
The problem persists with all other Javascript files disabled.
Your code is fine. The problem is that setting event handlers in the DOM 0 way doesn't ensure that they won't replaced by other code.
You may try the new W3C standard addEventListener and the IE version attachEvent, because the handlers you attach by them cannot be replaced by 3rd party code.
// window.onload W3C cross-browser with a fallback
function addLoadEvent(func) {
if (window.addEventListener)
window.addEventListener("load", func, false);
else if (window.attachEvent)
window.attachEvent("onload", func);
else { // fallback
var old = window.onload;
window.onload = function() {
if (old) old();
func();
};
}
}
Note, that IE will execute the function in reversed order not in the order you added them (if this is a concern).
Finally, I don't know when you want to run your code, but if you don't want to wait for images to load you can execute your functions earlier then window.onload.
Dean Edwards has a nice script which will let you to do that.
With this you can attach your functions for an earlier event: document.ready (DOMContentLoaded)
// document.ready
function addLoadEvent(func) {
if (typeof func == "function") {
addLoadEvent.queue.push(func);
}
}
addLoadEvent.queue = [];
//////////////////////////////////////////////////////////////////////////////
// Dean Edwards/Matthias Miller/John Resig
function init() {
// quit if this function has already been called
if (arguments.callee.done) return;
// flag this function so we don't do the same thing twice
arguments.callee.done = true;
// kill the timer
if (_timer) clearInterval(_timer);
// do stuff: execute the queue
var que = addLoadEvent.queue;
var len = que.length;
for(var i = 0; i < len; i++) {
if (typeof que[i] == "function") {
que[i]();
}
}
};
/* for Mozilla/Opera9 */
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", init, false);
}
/* for Internet Explorer */
/*#cc_on #*/
/*#if (#_win32)
document.write("<script id=__ie_onload defer src=javascript:void(0)>"
+"<\/script>");
var script = document.getElementById("__ie_onload");
script.onreadystatechange = function() {
if (this.readyState == "complete") {
init(); // call the onload handler
}
};
/*#end #*/
/* for Safari */
if (/WebKit/i.test(navigator.userAgent)) { // sniff
var _timer = setInterval(function() {
if (/loaded|complete/.test(document.readyState)) {
init(); // call the onload handler
}
}, 10);
}
/* for other browsers */
window.onload = init;
Note: the usage is the same for both methods as it was for your version.
I want to call a function after a document loads, but the document may or may not have finished loading yet. If it did load, then I can just call the function. If it did NOT load, then I can attach an event listener. I can't add an eventlistener after onload has already fired since it won't get called. So how can I check if the document has loaded? I tried the code below but it doesn't entirely work. Any ideas?
var body = document.getElementsByTagName('BODY')[0];
// CONDITION DOES NOT WORK
if (body && body.readyState == 'loaded') {
DoStuffFunction();
} else {
// CODE BELOW WORKS
if (window.addEventListener) {
window.addEventListener('load', DoStuffFunction, false);
} else {
window.attachEvent('onload', DoStuffFunction);
}
}
There's no need for all the code mentioned by galambalazs. The cross-browser way to do it in pure JavaScript is simply to test document.readyState:
if (document.readyState === "complete") { init(); }
This is also how jQuery does it.
Depending on where the JavaScript is loaded, this can be done inside an interval:
var readyStateCheckInterval = setInterval(function() {
if (document.readyState === "complete") {
clearInterval(readyStateCheckInterval);
init();
}
}, 10);
In fact, document.readyState can have three states:
Returns "loading" while the document is loading, "interactive" once it is finished parsing but still loading sub-resources, and "complete" once it has loaded.
-- document.readyState at Mozilla Developer Network
So if you only need the DOM to be ready, check for document.readyState === "interactive". If you need the whole page to be ready, including images, check for document.readyState === "complete".
No need for a library. jQuery used this script for a while, btw.
http://dean.edwards.name/weblog/2006/06/again/
// Dean Edwards/Matthias Miller/John Resig
function init() {
// quit if this function has already been called
if (arguments.callee.done) return;
// flag this function so we don't do the same thing twice
arguments.callee.done = true;
// kill the timer
if (_timer) clearInterval(_timer);
// do stuff
};
/* for Mozilla/Opera9 */
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", init, false);
}
/* for Internet Explorer */
/*#cc_on #*/
/*#if (#_win32)
document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
var script = document.getElementById("__ie_onload");
script.onreadystatechange = function() {
if (this.readyState == "complete") {
init(); // call the onload handler
}
};
/*#end #*/
/* for Safari */
if (/WebKit/i.test(navigator.userAgent)) { // sniff
var _timer = setInterval(function() {
if (/loaded|complete/.test(document.readyState)) {
init(); // call the onload handler
}
}, 10);
}
/* for other browsers */
window.onload = init;
You probably want to use something like jQuery, which makes JS programming easier.
Something like:
$(document).ready(function(){
// Your code here
});
Would seem to do what you are after.
if(document.readyState === 'complete') {
DoStuffFunction();
} else {
if (window.addEventListener) {
window.addEventListener('load', DoStuffFunction, false);
} else {
window.attachEvent('onload', DoStuffFunction);
}
}
If you actually want this code to run at load, not at domready (ie you need the images to be loaded as well), then unfortunately the ready function doesn't do it for you. I generally just do something like this:
Include in document javascript (ie always called before onload fired):
var pageisloaded=0;
window.addEvent('load',function(){
pageisloaded=1;
});
Then your code:
if (pageisloaded) {
DoStuffFunction();
} else {
window.addEvent('load',DoStuffFunction);
}
(Or the equivalent in your framework of preference.) I use this code to do precaching of javascript and images for future pages. Since the stuff I'm getting isn't used for this page at all, I don't want it to take precedence over the speedy download of images.
There may be a better way, but I've yet to find it.
Mozila Firefox says that onreadystatechange is an alternative to DOMContentLoaded.
// alternative to DOMContentLoaded
document.onreadystatechange = function () {
if (document.readyState == "complete") {
initApplication();
}
}
In DOMContentLoaded the Mozila's doc says:
The DOMContentLoaded event is fired when the document has been
completely loaded and parsed, without waiting for stylesheets, images,
and subframes to finish loading (the load event can be used to detect
a fully-loaded page).
I think load event should be used for a full document+resources loading.
The above one with JQuery is the easiest and mostly used way. However you can use pure javascript but try to define this script in the head so that it is read at the beginning. What you are looking for is window.onload event.
Below is a simple script that I created to run a counter. The counter then stops after 10 iterations
window.onload=function()
{
var counter = 0;
var interval1 = setInterval(function()
{
document.getElementById("div1").textContent=counter;
counter++;
if(counter==10)
{
clearInterval(interval1);
}
},1000);
}
Try this:
var body = document.getElementsByTagName('BODY')[0];
// CONDITION DOES NOT WORK
if ((body && body.readyState == 'loaded') || (body && body.readyState == 'complete') ) {
DoStuffFunction();
} else {
// CODE BELOW WORKS
if (window.addEventListener) {
window.addEventListener('load', DoStuffFunction, false);
} else {
window.attachEvent('onload',DoStuffFunction);
}
}
I have other solution, my application need to be started when new object of MyApp is created, so it looks like:
function MyApp(objId){
this.init=function(){
//.........
}
this.run=function(){
if(!document || !document.body || !window[objId]){
window.setTimeout(objId+".run();",100);
return;
}
this.init();
};
this.run();
}
//and i am starting it
var app=new MyApp('app');
it is working on all browsers, that i know.