2460

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.

6

39 Answers 39

1
2
0
(function(f){ if(document.readyState != "loading") f(); else document.addEventListener("DOMContentLoaded", f); })(function(){ console.log("The Document is ready"); }); 
Sign up to request clarification or add additional context in comments.

3 Comments

What does this add that the other answers do not?
It uses a self contained closure (doesn't populate the global "window" scope), it works on all browser and is very compact. I dont see any other answers like it.
It also works even after the DOM has already loaded (like jQuery.ready does), which most of these answers fail to do.
0

Most vanilla JS Ready functions do NOT consider the scenario where the DOMContentLoaded handler is set after the document is already loaded - Which means the function will never run. This can happen if you look for DOMContentLoaded within an async external script (<script async src="file.js"></script>).

The code below checks for DOMContentLoaded only if the document's readyState isn't already interactive or complete.

var DOMReady = function(callback) { document.readyState === "interactive" || document.readyState === "complete" ? callback() : document.addEventListener("DOMContentLoaded", callback()); }; DOMReady(function() { //DOM ready! }); 

If you want to support IE aswell:

var DOMReady = function(callback) { if (document.readyState === "interactive" || document.readyState === "complete") { callback(); } else if (document.addEventListener) { document.addEventListener('DOMContentLoaded', callback()); } else if (document.attachEvent) { document.attachEvent('onreadystatechange', function() { if (document.readyState != 'loading') { callback(); } }); } }; DOMReady(function() { // DOM ready! }); 

Comments

0

Works in all known browsers (tested via BrowserStack). IE6+, Safari 1+, Chrome 1+, Opera, etc. Uses DOMContentLoaded, with fallbacks to document.documentElement.doScroll() and window.onload.

/*! https://github.com/Kithraya/DOMContentLoaded v1.2.6 | MIT License */ DOMContentLoaded.version = "1.2.6"; function DOMContentLoaded() { "use strict"; var ael = 'addEventListener', rel = 'removeEventListener', aev = 'attachEvent', dev = 'detachEvent'; var alreadyRun = false, // for use in the idempotent function ready() funcs = arguments; // old versions of JS return '[object Object]' for null. function type(obj) { return (obj === null) ? 'null' : Object.prototype.toString.call(obj).slice(8,-1).toLowerCase() } function microtime() { return + new Date() } /* document.readyState === 'complete' reports correctly in every browser I have tested, including IE. But IE6 to 10 don't return the correct readyState values as per the spec: readyState is sometimes 'interactive', even when the DOM isn't accessible in IE6/7 so checking for the onreadystatechange event like jQuery does is not optimal readyState is complete at basically the same time as 'window.onload' (they're functionally equivalent, within a few tenths of a second) Accessing undefined properties of a defined object (document) will not throw an error (in case readyState is undefined). */ // Check for IE < 11 via conditional compilation /// values: 5?: IE5, 5.5?: IE5.5, 5.6/5.7: IE6/7, 5.8: IE8, 9: IE9, 10: IE10, 11*: (IE11 older doc mode), undefined: IE11 / NOT IE var jscript_version = Number( new Function("/*@cc_on return @_jscript_version; @*\/")() ) || NaN; // check if the DOM has already loaded if (document.readyState === 'complete') { ready(null); return; } // here we send null as the readyTime, since we don't know when the DOM became ready. if (jscript_version < 9) { doIEScrollCheck(); return; } // For IE<9 poll document.documentElement.doScroll(), no further actions are needed. /* Chrome, Edge, Firefox, IE9+, Opera 9+, Safari 3.1+, Android Webview, Chrome for Android, Edge Mobile, Firefox for Android 4+, Opera for Android, iOS Safari, Samsung Internet, etc, support addEventListener And IE9+ supports 'DOMContentLoaded' */ if (document[ael]) { document[ael]("DOMContentLoaded", ready, false); window[ael]("load", ready, false); // fallback to the load event in case addEventListener is supported, but not DOMContentLoaded } else if (aev in window) { window[aev]('onload', ready); /* Old Opera has a default of window.attachEvent being falsy, so we use the in operator instead https://dev.opera.com/blog/window-event-attachevent-detachevent-script-onreadystatechange/ Honestly if somebody is using a browser so outdated AND obscure (like Opera 7 where neither addEventListener nor "DOMContLoaded" is supported, they deserve to wait for the full page). I CBA testing whether readyState === 'interactive' is truly interactive in browsers designed in 2003. I just assume it isn't (like in IE6-8). */ } else { // fallback to queue window.onload that will always work addOnload(ready); } // This function allows us to preserve any original window.onload handlers (in super old browsers where this is even necessary), // while keeping the option to chain onloads, and dequeue them. function addOnload(fn) { var prev = window.onload; // old window.onload, which could be set by this function, or elsewhere // we add a function queue list to allow for dequeueing // addOnload.queue is the queue of functions that we will run when when the DOM is ready if ( type( addOnload.queue ) !== 'array') { addOnload.queue = []; if ( type(prev) === 'function') { addOnload.queue.push( prev ); } // add the previously defined event handler } if (typeof fn === 'function') { addOnload.queue.push(fn) } window.onload = function() { // iterate through the queued functions for (var i = 0; i < addOnload.queue.length; i++) { addOnload.queue[i]() } }; } // remove a queued window.onload function from the chain (simplified); function dequeueOnload(fn) { var q = addOnload.queue, i = 0; // sort through the queued functions in addOnload.queue until we find `fn` if (type( q ) === 'array') { // if found, remove from the queue for (; i < q.length; i++) { ;;(fn === q[i]) ? q.splice(i, 1) : 0; } // void( (fn === q[i]) ? q.splice(i, 1) : 0 ) } } function ready(ev) { // idempotent event handler function if (alreadyRun) {return} alreadyRun = true; // this time is when the DOM has loaded (or if all else fails, when it was actually possible to inference the DOM has loaded via a 'load' event) // perhaps this should be `null` if we have to inference readyTime via a 'load' event, but this functionality is better. var readyTime = microtime(); detach(); // detach any event handlers // run the functions for (var i=0; i < funcs.length; i++) { var func = funcs[i]; if (type(func) === 'function') { func.call(document, { 'readyTime': (ev === null ? null : readyTime), 'funcExecuteTime': microtime() }, func); // jquery calls 'ready' with `this` being set to document, so we'll do the same. } } } function detach() { if (document[rel]) { document[rel]("DOMContentLoaded", ready); window[rel]("load", ready); } else if (dev in window) { window[dev]("onload", ready); } else { dequeueOnload(ready); } } function doIEScrollCheck() { // for use in IE < 9 only. if ( window.frameElement ) { // we're in an <iframe> or similar // the document.documentElemeent.doScroll technique does not work if we're not at the top-level (parent document) try { window.attachEvent("onload", ready); } catch (e) { } // attach to onload if were in an <iframe> in IE as there's no way to tell otherwise return; } try { document.documentElement.doScroll('left'); // when this statement no longer throws, the DOM is accessible in old IE } catch(error) { setTimeout(function() { (document.readyState === 'complete') ? ready() : doIEScrollCheck(); }, 50); return; } ready(); } } 

Usage:

<script> DOMContentLoaded(function(e) { console.log(e) }); </script> 

Comments

-1

This was a good https://stackoverflow.com/a/11810957/185565 poor man's solution. One comment considered a counter to bail out in case of emergency. This is my modification.

function doTheMagic(counter) { alert("It worked on " + counter); } // wait for document ready then call handler function var checkLoad = function(counter) { counter++; if (document.readyState != "complete" && counter<1000) { var fn = function() { checkLoad(counter); }; setTimeout(fn,10); } else doTheMagic(counter); }; checkLoad(0); 

Comments

-1

Edit of the edit of @duskwuff to support Internet Explorer 8 too. The difference is a new call to the function test of the regex and the setTimeout with an anonymous function.

Also, I set the timeout to 99.

function ready(f){/in/.test(document.readyState)?setTimeout(function(){ready(f);},99):f();} 

Comments

-2

The ready function in jQuery does a number of things. Frankly, I don't see that point of replacing it unless you have amazingly small output from your website. jQuery is a pretty tiny library, and it handles all sorts of cross-browser things you'll need later.

Anyway, there's little point in posting it here, just open up jQuery and look at the bindReady method.

It starts by calling either document.addEventListener("DOMContentLoaded") or document.attachEvent('onreadystatechange') depending on the event model, and goes on from there.

Comments

-2

Try this:

function ready(callback){ if(typeof callback === "function"){ document.addEventListener("DOMContentLoaded", callback); window.addEventListener("load", callback); }else{ throw new Error("Sorry, I can not run this!"); } } ready(function(){ console.log("It worked!"); }); 

1 Comment

Lol you're gonna run the callback twice
-4

In short, instead of the $(document).ready() used in jQuery, we can use a JavaScript method:

<script> document.addEventListener("DOMContentLoaded", function_name, false); function function_name(){ statements; } </script> 

Thus, when the page is ready i.e. DOMContentLoaded only then the function function_name() will be invoked.

1 Comment

Whenever a high-voted question appears on the front page, it's often worth checking the dates to make sure you're not responding to a very old posting. (One scenario I might respond is if over the years there is a new solution not present originally. DOMContentLoaded was definitely already mentioned though.)
-7

If you want to support Internet Explorer 7+ (no quirks, compatibility and other pain), last Chrome, last Safari, last Firefox and no iframes - this will be enough:

is_loaded = false callbacks = [] loaded = -> is_loaded = true for i in [0...callbacks.length] callbacks[i].call document callbacks = [] content_loaded = -> document.removeEventListener "DOMContentLoaded", content_loaded, true loaded() state_changed = -> if document.readyState is "complete" document.detachEvent "onreadystatechange", state_changed loaded() if !!document.addEventListener document.addEventListener "DOMContentLoaded", content_loaded, true else document.attachEvent "onreadystatechange", state_changed dom_ready = (callback) -> if is_loaded callback.call document else callbacks.push callback 

2 Comments

That most definitely isn't javascript.
Looks like someone writes CoffeeScript.
1
2

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.