Difference between " readyState === 'Interactive' " and " Jquery.ready() " - javascript

Today I am Playing with DOM readyState,And I find something strange in JQuery.ready(),
JQuery.ready() event occurs before DOMContentload event then i put interactive in my code
like : document.readyState === "interactive"
Then this code is load before Jquery.ready() So, I have a question , is
JQuery.ready() is equal or similar to document.readyState === "interactive?
and What Technique JQuery Applies in there .ready() Event ?
How I apply this .ready() in my pure Javascript ?
I read lots of similar post of that type but no one gives the exact solution to implement JQuery.ready() on JavaScript they all load after DOMContentload not when .ready().
Here MY Jsfiddle

when we browse something the document.readyState can be one of the following:
loading
The document is still loading.
interactive
The document has finished loading and the document has been parsed but sub-resources such as images, stylesheets, and frames are still loading.
complete
The document and all sub-resources have finished loading. The state indicates that the load event is about to fire.
JQuery.ready() is not equal or similar to document.readyState === "interactive because .redyState return a string interactive or loading browser is syncing data from server, when it done it return complete string and create a load event.
The jQuery uses the above functionality to create the doc.ready() for their library.
if you wish to run your function after loading the document, there are many ways... but one of these
function myFun(){
// All your JS code which will use in your document
console.log("Hey now I am ready to run");
}
// just call the myFun() in a eventListene function as callback function
//the myFun will run after the
document.addEventListener('DOMContentLoaded', myFun, false);
A little idea what jQuery does (which will work wherever the script tag is placed).
const ready =(fun) => {
if(document.ready == 'interactive' || document.readyState =="complete"){
// calling function
setTimeout(fun, 1);
}
// we can also implement by event listner
else {
document.addEventListener("DOMContentLoaded", fun);
}
}
ready(() => {
// This is the functin whitch pass to the ready function
console.log("I am ready.")
});
hey I know that is not good but the idea behind it is that.
A little idea what jQuery does (which will work wherever the script tag is placed).
The alternative ways are
if supported, it tries the standard:
window.addEventListener('load', fn, false )
with a fallback to:
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);
window.attachEvent("onload", fn);
the information taken from :document.ready on MDN

Related

Javascript load vs ready vs domready vs DOMContentLoaded events

I am a bit lost in the "start up" events - there are so many different events and are named differently in the DOM and in various frameworks like jQuery. What are all possible start up events? How do they differ? Can you show a simple timeline to demonstrate in which order are these events fired?
.ready()
While JavaScript provides the load event for executing code when a
page is rendered, this event does not get triggered until all assets
such as images have been completely received. In most cases, the
script can be run as soon as the DOM hierarchy has been fully
constructed. The handler passed to .ready() is guaranteed to be
executed after the DOM is ready, so this is usually the best place to
attach all other event handlers and run other jQuery code. When using
scripts that rely on the value of CSS style properties, it's important
to reference external stylesheets or embed style elements before
referencing the scripts.
In cases where code relies on loaded assets (for example, if the
dimensions of an image are required), the code should be placed in a
handler for the load event instead.
The .ready() method is generally incompatible with the attribute. If load must be used, either do not use .ready()
or use jQuery's .load() method to attach load event handlers to the
window or to more specific items, like images.
Ref: http://api.jquery.com/ready/
.load()
This method is a shortcut for .on( "load", handler ).
The load event is sent to an element when it and all sub-elements have
been completely loaded. This event can be sent to any element
associated with a URL: images, scripts, frames, iframes, and the
window object.
In general, it is not necessary to wait for all images to be fully
loaded. If code can be executed earlier, it is usually best to place
it in a handler sent to the .ready() method.
Ref: http://api.jquery.com/load-event/
GlobalEventHandlers.onload
The load event fires at the end of the document loading process. At
this point, all of the objects in the document are in the DOM, and all
the images and sub-frames have finished loading.
There are also Gecko-Specific DOM Events like DOMContentLoaded and
DOMFrameContentLoaded (which can be handled using
EventTarget.addEventListener()) which are fired after the DOM for the
page has been constructed, but do not wait for other resources to
finish loading.
Cross-browser fallback
Internet Explorer 8 supports the readystatechange event, which can be
used to detect that the DOM is ready. In earlier version of Internet
Explorer, this state can be detected by regularily trying to execute
document.documentElement.doScroll("left");, as this snippet will throw
an error until the DOM is ready.
General-purpose JS libraries such as jQuery offer cross-browser
methods to detect that the DOM is ready. There are also standalone
scripts that offer this feature : contentloaded.js (supports only one
listener) and jquery.documentReady.js (doesn't depend on jQuery,
despite its name). Ref:
https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers.onload
Code:
document.addEventListener("DOMContentLoaded", function (event) {
console.log("DOM fully loaded and parsed");
});
function load() {
console.log("load event detected!");
}
window.onload = load;
$(document).ready(function () {
console.log('ready');
});
$(window).load(function () {
console.log('loaded');
});
Timeline demo: http://jsfiddle.net/HgJ33/
Can be interesting to write down the different frameworks and their events:
Here is test series using jsFiddle. Same html, different frameworks, difference in ms.
Mootools
window.onload = function () {
var now = new Date().getTime() - time;
console.log(now, 'onload') // 14 ms
};
window.addEvent('load', function () {
var now = new Date().getTime() - time;
console.log(now, 'load') // 15 ms
});
window.addEvent('domready', function () {
var now = new Date().getTime() - time;
console.log(now, 'domready') // 1 ms
});
jQuery
window.onload = function () {
var now = new Date().getTime() - time;
console.log(now, 'onload') // 20 ms
};
$(document).on('DOMContentLoaded', function () {
var now = new Date().getTime() - time;
console.log(now, 'DOMContentLoaded') // 10 ms
});
$(document).on('ready', function () {
var now = new Date().getTime() - time;
console.log(now, 'ready') // 20 ms
});
Dojo Toolkit
dojo.addOnLoad(function() {
//do stuff
});
YUI
YUI().use('*',function(Y) {
Y.on("domready", function() {
//do stuff
}, Y, "The DOMContentLoaded event fired. The DOM is now safe to modify via script.");
});
Prototype
document.observe("dom:loaded", function() {
//do stuff
});
Sencha JS
Ext.onReady(function() {
//do stuff
});
In general, previosus answers are very good and full.
But one important difference between .ready() and DOMContentLoaded event exists.
Most browsers provide similar functionality in the form of a
DOMContentLoaded event. However, jQuery's .ready() method differs in
an important and useful way: If the DOM becomes ready and the browser
fires DOMContentLoaded before the code calls .ready( handler ), the
function handler will still be executed. In contrast, a
DOMContentLoaded event listener added after the event fires is never
executed.
Ref. https://api.jquery.com/ready/
As we see from this, .ready() is executed at least once in all cases.
For example, in browser console we may define
>> function sample()
{
console.log('This is sample.');
$( document ).ready(function ()
{
console.log("Ready is working in all cases.")
});
}
undefined
and in result we have
>> sample();
undefined
This is sample. debugger eval code:3:11
Ready is working in all cases. debugger eval code:7:13
>> sample();
undefined
This is sample. debugger eval code:3:11
Ready is working in all cases. debugger eval code:7:13
It is better to think from the perspective of what you want and which browsers to support.
To make manipulations in Document Object Model (DOM) you will have to make sure the HTML page is loaded over network and parsed into a tree. One way of tackling this is by writing all code at end of the HTML file which leads to processing those javascript only after parsing the HTML. The other newer standard way is to listen for the DOMReady or DOMContentLoaded event or ready event to make sure the handler is run only after DOM is ready
After DOM tree is built browser will request for images, audio, video etc. After all these resources are loaded window load event is fired ,now the page is ready to be rendered fully.
So basically you should just think if your code can be executed with the DOM tree ready, or do you need everything loaded to run your code. If the native javascript implementation of DOM ready doesnt cover all the browsers you need to support, you can go for jQuery DOMready that is the reason why its made.

How to know if window "load" event was fired already

I'm writing a Javascript script.
This script will probably be loaded asynchronously (AMD format).
In this script, I'd like to do nothing important until the window.load event was fired.
So I listen to the window "load" event.
But if the script is loaded after window.load event... how can I know window.load was already fired?
And of course I don't want to add something in any other scripts (they are all loaded async, the problem is the same) :)
Edit :
Imagine an HTML doc with no Javascript in it at all.
Than someone insert in this doc a tag, and this script tag loads my Javascript file.
This will execute my script.
How this script can know if window.load was already fired ?
No jQuery, not any script in the HTML doc before mine.
Is it possible to know ??
I found the window.document.readystate property. This property is for document "ready" event I guess, not for window "load".
Is there anything similar for window "load" event ?
The easiest solution might be checking for document.readyState == 'complete', see http://www.w3schools.com/jsref/prop_doc_readystate.asp
Quick Answer
To quickly answer the question's title:
document.readyState === 'complete'
Deeper Example
Below is a nice helper if you want to call code upon a window load, while still handling the case where the window may have already loaded by the time your code runs.
function winLoad(callback) {
if (document.readyState === 'complete') {
callback();
} else {
window.addEventListener("load", callback);
}
}
winLoad(function() {
console.log('Window is loaded');
});
Note: code snippets on here actually don't run in the same window context so document.readyState === 'complete' actually evaluates to false when you run this. If you put the same into your console right now for this window it should evaluate as true.
See also: What is the non-jQuery equivalent of '$(document).ready()'?
Handling the Edge Case from #IgorBykov via Comments
Igor brought up an interesting issue in the comments, which the following code can try to handle given a best-effort-timeout.
The problem is that the document.readyState can be complete before the load event fires. I'm not certain what potential problems this may cause.
Some Documentation About the Flow and Event Firing
https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState
Complete: The state indicates that the load event is about to fire.
https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event
Gives a live example of event firing ie:
readyState: interactive
Event Fired: DOMContentLoaded
readyState: complete
Event Fired: load
There's a brief moment where the readyState may be complete before load fires. I'm not sure what issues you may run into during this period.
The below code registers the load event listener, and sets a timeout to check the readyState. By default it will wait 200ms before checking the readyState. If the load event fires before the timeout we make sure to prevent firing the callback again. If we get to the end of the timeout and load wasn't fired we check the readyState and make sure to avoid a case where the load event could potentially still fire at a later time.
Depending on what you're trying to accomplish you may want to run the load callback no matter what (remove the if (!called) { check). In your callback you might want to wrap potential code in a try/catch statement or check for something that you can gate the execution on so that when it calls twice it only performs the work when everything is available that you expect.
function winLoad(callback, timeout = 200) {
let called = false;
window.addEventListener("load", () => {
if (!called) {
called = true;
callback();
}
});
setTimeout(() => {
if (!called && document.readyState === 'complete') {
called = true;
callback();
}
}, timeout);
}
winLoad(function() {
console.log('Window is loaded');
});
Browser navigation performance loadEventEnd metric can be used to determinate if load event was triggered:
let navData = window.performance.getEntriesByType("navigation");
if (navData.length > 0 && navData[0].loadEventEnd > 0)
{
console.log('Document is loaded');
} else {
console.log('Document is not loaded');
}
Based on #CTS_AE's approach, I have put together a solution for envrionments where:
window.addEventListener('load', activateMyFunction); and
window.addEventListener('DOMContentLoaded', activateMyFunction);
don't work.
It requires a single character substitution (eg. from
window.addEventListener('load', activateMyFunction);
to
window_addEventListener('load', activateMyFunction);)
The function window_addEventListener() looks like this:
const window_addEventListener = (eventName, callback, useCapture = false) => {
if ((document.readyState === 'interactive') || (document.readyState === 'complete')) {
callback();
}
}
If you don't want to use jQuery, the logic it uses is:
if( !document.body )
setTimeout( checkAgain, 1 );
So between the windows loaded event and checking if the body property of the document is available, you can check if the DOM is ready
Easy method:
window.onload = (event) => {
console.log('page is fully loaded');
};
You can find other methods from resources here.
what about overriding window.load?
window._load = window.load;
window.load = function(){
window.loaded = true;
window._load();
}
Then check for
if (window.loaded != undefined && window.loaded == true){
//do stuff
}

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

This question already has answers here:
$(document).ready equivalent without jQuery
(39 answers)
Closed 6 years ago.
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:
<body onload="myFunction()">
Or I can even try at the bottom of the page after everything, but the end body or html tag like:
<script type="text/javascript">
myFunction();
</script>
What is a cross-browser(old/new)-compliant method of issuing one or more functions in a manner like jQuery's $.ready()?
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.
<!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>
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 be IE
document.attachEvent("onreadystatechange", readyStateChange);
window.attachEvent("onload", ready);
}
readyEventHandlersInstalled = true;
}
}
})("docReady", window);
The latest version of the code is shared publicly on GitHub at https://github.com/jfriend00/docReady
Usage:
// pass a function reference
docReady(fn);
// use an anonymous function
docReady(function() {
// code here
});
// pass a function reference and a context
// the context will be passed to the function as the first argument
docReady(fn, context);
// use an anonymous function with a context
docReady(function(context) {
// code here that can use the context argument that was passed to docReady
}, ctx);
This has been tested in:
IE6 and up
Firefox 3.6 and up
Chrome 14 and up
Safari 5.1 and up
Opera 11.6 and up
Multiple iOS devices
Multiple Android devices
Working implementation and test bed: http://jsfiddle.net/jfriend00/YfD3C/
Here's a summary of how it works:
Create an IIFE (immediately invoked function expression) so we can have non-public state variables.
Declare a public function docReady(fn, context)
When docReady(fn, context) is called, check if the ready handler has already fired. If so, just schedule the newly added callback to fire right after this thread of JS finishes with setTimeout(fn, 1).
If the ready handler has not already fired, then add this new callback to the list of callbacks to be called later.
Check if the document is already ready. If so, execute all ready handlers.
If we haven't installed event listeners yet to know when the document becomes ready, then install them now.
If document.addEventListener exists, then install event handlers using .addEventListener() for both "DOMContentLoaded" and "load" events. The "load" is a backup event for safety and should not be needed.
If document.addEventListener doesn't exist, then install event handlers using .attachEvent() for "onreadystatechange" and "onload" events.
In the onreadystatechange event, check to see if the document.readyState === "complete" and if so, call a function to fire all the ready handlers.
In all the other event handlers, call a function to fire all the ready handlers.
In the function to call all the ready handlers, check a state variable to see if we've already fired. If we have, do nothing. If we haven't yet been called, then loop through the array of ready functions and call each one in the order they were added. Set a flag to indicate these have all been called so they are never executed more than once.
Clear the function array so any closures they might be using can be freed.
Handlers registered with docReady() are guaranteed to be fired in the order they were registered.
If you call docReady(fn) after the document is already ready, the callback will be scheduled to execute as soon as the current thread of execution completes using setTimeout(fn, 1). This allows the calling code to always assume they are async callbacks that will be called later, even if later is as soon as the current thread of JS finishes and it preserves calling order.
If you are doing VANILLA plain JavaScript without jQuery, then you must use (Internet Explorer 9 or later):
document.addEventListener("DOMContentLoaded", function(event) {
// Your code to run since DOM is loaded and ready
});
Above is the equivalent of jQuery .ready:
$(document).ready(function() {
console.log("Ready!");
});
Which ALSO could be written SHORTHAND like this, which jQuery will run after the ready even occurs.
$(function() {
console.log("ready!");
});
NOT TO BE CONFUSED with BELOW (which is not meant to be DOM ready):
DO NOT use an IIFE like this that is self executing:
Example:
(function() {
// Your page initialization code here - WRONG
// The DOM will be available here - WRONG
})();
This IIFE will NOT wait for your DOM to load. (I'm even talking about latest version of Chrome browser!)
I would like to mention some of the possible ways here together with a pure javascript trick which works across all browsers:
// with jQuery
$(document).ready(function(){ /* ... */ });
// shorter jQuery version
$(function(){ /* ... */ });
// without jQuery (doesn't work in older IEs)
document.addEventListener('DOMContentLoaded', function(){
// your code goes here
}, false);
// and here's the trick (works everywhere)
function r(f){/in/.test(document.readyState)?setTimeout('r('+f+')',9):f()}
// use like
r(function(){
alert('DOM Ready!');
});
The trick here, as explained by the original author, is that we are checking the document.readyState property. If it contains the string in (as in uninitialized and loading, the first two DOM ready states out of 5) we set a timeout and check again. Otherwise, we execute the passed function.
And here's the jsFiddle for the trick which works across all browsers.
Thanks to Tutorialzine for including this in their book.
Tested in IE9, and latest Firefox and Chrome and also supported in IE8.
document.onreadystatechange = function () {
var state = document.readyState;
if (state == 'interactive') {
init();
} else if (state == 'complete') {
initOnCompleteLoad();
}
}​;
Example: http://jsfiddle.net/electricvisions/Jacck/
UPDATE - reusable version
I have just developed the following. It's a rather simplistic equivalent to jQuery or Dom ready without backwards compatibility. It probably needs further refinement. Tested in latest versions of Chrome, Firefox and IE (10/11) and should work in older browsers as commented on. I'll update if I find any issues.
window.readyHandlers = [];
window.ready = function ready(handler) {
window.readyHandlers.push(handler);
handleState();
};
window.handleState = function handleState () {
if (['interactive', 'complete'].indexOf(document.readyState) > -1) {
while(window.readyHandlers.length > 0) {
(window.readyHandlers.shift())();
}
}
};
document.onreadystatechange = window.handleState;
Usage:
ready(function () {
// your code here
});
It's written to handle async loading of JS but you might want to sync load this script first unless you're minifying. I've found it useful in development.
Modern browsers also support async loading of scripts which further enhances the experience. Support for async means multiple scripts can be downloaded simultaneously all while still rendering the page. Just watch out when depending on other scripts loaded asynchronously or use a minifier or something like browserify to handle dependencies.
The good folks at HubSpot have a resource where you can find pure Javascript methodologies for achieving a lot of jQuery goodness - including ready
http://youmightnotneedjquery.com/#ready
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();
});
}
}
example inline usage:
ready(function() { alert('hello'); });
I'm not quite sure what you're asking, but maybe this can help:
window.onload = function(){
// Code. . .
}
Or:
window.onload = main;
function main(){
// Code. . .
}
Your method (placing script before the closing body tag)
<script>
myFunction()
</script>
</body>
</html>
is a reliable way to support old and new browsers.
Ready
function ready(fn){var d=document;(d.readyState=='loading')?d.addEventListener('DOMContentLoaded',fn):fn();}
Use like
ready(function(){
//some code
});
For self invoking code
(function(fn){var d=document;(d.readyState=='loading')?d.addEventListener('DOMContentLoaded',fn):fn();})(function(){
//Some Code here
//DOM is avaliable
//var h1s = document.querySelector("h1");
});
Support: IE9+
Here's a cleaned-up, non-eval-using version of Ram-swaroop's "works in all browsers" variety--works in all browsers!
function onReady(yourMethod) {
var readyStateCheckInterval = setInterval(function() {
if (document && document.readyState === 'complete') { // Or 'interactive'
clearInterval(readyStateCheckInterval);
yourMethod();
}
}, 10);
}
// use like
onReady(function() { alert('hello'); } );
It does wait an extra 10 ms to run, however, so here's a more complicated way that shouldn't:
function onReady(yourMethod) {
if (document.readyState === 'complete') { // Or also compare to 'interactive'
setTimeout(yourMethod, 1); // Schedule to run immediately
}
else {
readyStateCheckInterval = setInterval(function() {
if (document.readyState === 'complete') { // Or also compare to 'interactive'
clearInterval(readyStateCheckInterval);
yourMethod();
}
}, 10);
}
}
// Use like
onReady(function() { alert('hello'); } );
// Or
onReady(functionName);
See also How to check if DOM is ready without a framework?.
document.ondomcontentready=function(){} should do the trick, but it doesn't have full browser compatibility.
Seems like you should just use jQuery min

How to check if DOM is ready without a framework?

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

onload from external js file

I'm writing a js script that people will add to their web site by adding a single line of code to the header or end of the body part of their HTML.
My question is how to do the onload right on the external js file. Will the code below work? Can't it possibly run after the onload of the document and miss the onload event?
function c_onload () { alert ('onload'); }
if (window.attachEvent) {window.attachEvent('onload', c_onload);}
else if (window.addEventListener) {window.addEventListener('load', c_onload, false);}
else {document.addEventListener('load', c_onload, false);}
(I can't use Jquery or any other library)
What is your last else-clause
else {document.addEventListener('load', c_onload, false);
for? It's rather useless, imho.
The following should be a cross-browser solution: It first checks for addEventListener(), then attachEvent() and falls back to onload = ...
function chain(f1, f2) {
return typeof f1 !== 'function' ? f2 : function() {
var r1 = f1.apply(this, arguments),
r2 = f2.apply(this, arguments);
return typeof r1 === 'undefined' ? r2 : (r1 && r2);
};
}
function addOnloadListener(func) {
if(window.addEventListener)
window.addEventListener('load', func, false);
else if(window.attachEvent)
window.attachEvent('onload', func);
else window.onload = chain(window.onload, func);
}
Also, what kgiannakakis stated
The reason is that browsers handle the onLoad event differently.
is not true: all major browsers handle window.onload the same way, ie the listener function gets executed after the external resources - including your external script - have been loaded. The problem lies with DOMContentLoaded - that's where the hacks with doScroll(), defer, onreadystatechange and whatever else someone has cooked up come to play.
Depending on your target audience, you may either want to drop the fallback code or even use it exclusively. My vote would go for dropping it.
I am afraid that if you can't use jQuery or some other library you need to reproduce a way good deal of their functionality. The reason is that browsers handle the onLoad event differently.
I recommend that you download jQuery's code and see how the documentready function is implemented.
The onLoad event is supposed to be run when the element it is attached to is loaded. But some browsers* misinpret this as "beforeload" or "sometime during load" so the safest option to be sure something is run after all html is loaded, is to add a call to the function on the bottom of the HTML source, like this:
...
<script type="text/javascript">
c_onload();
</script>
</body>
</html>
(* at least some versions of Safari for Windows I do beleave have this issue)

Categories

Resources