HiveBrain v1.2.0
Get Started
← Back to all entries
snippetjavascriptCritical

Vanilla JavaScript equivalent of jQuery's $.ready() - how to call a function when the page/DOM is ready for it

Submitted by: @import:stackoverflow-api··
0
Viewed 0 times
pagehowjqueryfunctiondomtheforvanillaequivalentwhen

Problem

With jQuery, we all know the wonderful .ready() function:

$('document').ready(function(){});


However, let's say I want to run a function that is written in standard JavaScript with no library backing it, and that I want to launch a function as soon as the page is ready to handle it. What's the proper way to approach this?

I know I can do:

window.onload="myFunction()";


Or I can use the body tag:




Or I can even try at the bottom of the page after everything, but the end body or html tag like:


myFunction();



What is a cross-browser(old/new)-compliant method of issuing one or more functions in a manner like jQuery's $.ready()?

Solution

The simplest thing to do in the absence of a framework that does all the cross-browser compatibility for you is to just put a call to your code at the end of the body. This is faster to execute than an onload handler because this waits only for the DOM to be ready, not for all images to load. And, this works in every browser.


Your HTML here

// self executing function here
(function() {
   // your page initialization code here
   // the DOM will be available here

})();


For modern browsers (anything from IE9 and newer and any version of Chrome, Firefox or Safari), if you want to be able to implement a jQuery like $(document).ready() method that you can call from anywhere (without worrying about where the calling script is positioned), you can just use something like this:

function docReady(fn) {
    // see if DOM is already available
    if (document.readyState === "complete" || document.readyState === "interactive") {
        // call on next available tick
        setTimeout(fn, 1);
    } else {
        document.addEventListener("DOMContentLoaded", fn);
    }
}


Usage:

docReady(function() {
    // DOM is loaded and ready for manipulation here
});


If you need full cross browser compatibility (including old versions of IE) and you don't want to wait for window.onload, then you probably should go look at how a framework like jQuery implements its $(document).ready() method. It's fairly involved depending upon the capabilities of the browser.

To give you a little idea what jQuery does (which will work wherever the script tag is placed).

If supported, it tries the standard:

document.addEventListener('DOMContentLoaded', fn, false);


with a fallback to:

window.addEventListener('load', fn, false )


or for older versions of IE, it uses:

document.attachEvent("onreadystatechange", fn);


with a fallback to:

window.attachEvent("onload", fn);


And, there are some work-arounds in the IE code path that I don't quite follow, but it looks like it has something to do with frames.

Here is a full substitute for jQuery's .ready() written in plain javascript:

```
(function(funcName, baseObj) {
// The public function name defaults to window.docReady
// but you can pass in your own object and own function name and those will be used
// if you want to put them in a different namespace
funcName = funcName || "docReady";
baseObj = baseObj || window;
var readyList = [];
var readyFired = false;
var readyEventHandlersInstalled = false;

// call this when the document is ready
// this function protects itself against being called more than once
function ready() {
if (!readyFired) {
// this must be set to true before we start calling callbacks
readyFired = true;
for (var i = 0; i < readyList.length; i++) {
// if a callback here happens to add new ready handlers,
// the docReady() function will see that it already fired
// and will schedule the callback to run right after
// this event loop finishes so all handlers will still execute
// in order and no new ones will be added to the readyList
// while we are processing the list
readyList[i].fn.call(window, readyList[i].ctx);
}
// allow any closures held by these functions to free
readyList = [];
}
}

function readyStateChange() {
if ( document.readyState === "complete" ) {
ready();
}
}

// This is the one public interface
// docReady(fn, context);
// the context argument is optional - if present, it will be passed
// as an argument to the callback
baseObj[funcName] = function(callback, context) {
if (typeof callback !== "function") {
throw new TypeError("callback for docReady(fn) must be a function");
}
// if ready has already fired, then just schedule the callback
// to fire asynchronously, but right away
if (readyFired) {
setTimeout(function() {callback(context);}, 1);
return;
} else {
// add the function and context to the list
readyList.push({fn: callback, ctx: context});
}
// if document already ready to go, schedule the ready function to run
if (document.readyState === "complete") {
setTimeout(ready, 1);
} else if (!readyEventHandlersInstalled) {
// otherwise if we don't have event handlers installed, install them
if (document.addEventListener) {
// first choice is DOMContentLoaded event
document.addEventListener("DOMContentLoaded", ready, false);
// backup is window load event
window.addEventListener("load", ready, false);
} else {
// must

Code Snippets

<!doctype html>
<html>
<head>
</head>
<body>
Your HTML here

<script>
// self executing function here
(function() {
   // your page initialization code here
   // the DOM will be available here

})();
</script>
</body>
</html>
function docReady(fn) {
    // see if DOM is already available
    if (document.readyState === "complete" || document.readyState === "interactive") {
        // call on next available tick
        setTimeout(fn, 1);
    } else {
        document.addEventListener("DOMContentLoaded", fn);
    }
}
docReady(function() {
    // DOM is loaded and ready for manipulation here
});
document.addEventListener('DOMContentLoaded', fn, false);
window.addEventListener('load', fn, false )

Context

Stack Overflow Q#9899372, score: 2678

Revisions (0)

No revisions yet.