how to know the first ready state of DOM - javascript

i am trying to get the first ready state of the DOM. the second, third, etc is not interesting me, but the first one. is there any trick to get the first ready state of DOM?
$(document).ready(function() {
// is it the first ready state?
});

There are 4 readyState possible values:
uninitialized - Has not started loading yet
loading - Is loading
interactive - Has loaded enough and the user can interact with it
complete - Fully loaded
To see it's value use this code:
document.onreadystatechange = function () {
if (document.readyState === YourChoice) {
// ...
}
}
I could not catch the uninitialized readyState. (but why should I need it?)
If you need a listener for complete load of the DOM, use:
document.addEventListener('DOMContentLoaded', YourListener);
or
document.addEventListener('load', YourListener);
or even
window.onload = YourListener;
for jquery:
$(document).on("DOMContentLoaded", function() { });
or
$(document).on("load", function() { });
or
$(window).on("load", function() { });

Ah, you're using jQuery. Have a look at the docs: There is only one ready event! I will never fire multiple times. Internally, this is even handled with a Promise, so it cannot fire multiple times.

Related

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
}

Execute a javascript function as last inside a page

I need to be sure that a certain script within a page is executed as last.
I thought of using JQuery
$(document).ready( ... )
but if there are more functions of this type, which is actually executed last?
There are many ways to delay the execution of a script.
There is no way to programatically detect all of them.
For a reliable solution you would have to reverse engine the code of each page you care about, figure out what it is doing (and when) and write your delay script specifically for that page. (For a value of "reliable" equal to "until they change the page").
$(document).ready( ... )
is not executed last. The last function executed ( so, after document ready ) is the one(s) from <body onload>.
Example : <body onload="myJSfunction();">
Here, the javascript myJSfunction is executed at the end, after $(document).ready( ... ).
This depends on the order in which you have registered them.
E.g:
$(document).ready( function() { alert("first"); });
$(document).ready( function() { alert("second"); });
$(document).ready( function() { alert("third"); });​
would alert "first" then "second" then "third"
So adding a <script> to the bottom of your page with an $(document).ready( yourfunction ); would suffice.
Theoretically you can do something like this:
// Form array of functions which sould be called with according order
$.readyArray = [function () { ... }, function () { ... }, function () { ... }, ...];
// just execute them in this order when onready event
$(document).ready(function() {
for (var i = 0; i < $.readyArray.length; i++) {
//apply, calls function in current context and pass arguments object
$.readyArray[i].apply(this,[arguments]);
}
});
If refactoring (as Quentin suggested) is not an option (e.g. you are updating a just part of a framework or a product), you can use four approaches, which should give you a good chance achieving what you need. See the following snippets with jQuery:
(1) Wait until 'document' is ready
By document is meant the visible DOM. The script will fire when all it should be rendered really rendered is.
$(document).ready(function() {
console.log('Document is ready.');
});
(2) Wait until top-level JS (Root) 'window' object is ready
The full root object can (will) be ready some time after the DOM is ready.
$(window).ready(function() {
console.log('Window is ready.');
});
(3) Wait until 'window' is fully loaded using .bind
This fires immediately after 'window' is ready, so your script can act on objects (elements) rendered during $(window).ready() above.
$(window).bind("load", function() {
console.log('Window bind is ready.');
});
(4) Wait until Ajax calls are completed
This is as far as you can go - the script will fire when 'window' is ready, loaded, all the code run and all the Ajax actions are completed. Unfortunately, since one Ajax can call another one, it can fire several times during the page load.
$(window).ajaxComplete(function() {
console.log('Window bind is ready, Ajax finished.');
}
In simple Javascript solution, you could call the javascript function at end of your HTML document inside the script tag. This works well when you are not using jQuery.
In case of jQuery you could use load method.The load event is sent to an element when it and all sub-elements have been completely loaded.
For more info look at
http://api.jquery.com/load-event/
Try this,
$(window).bind("load", function() {
//code here
});

execute function after complete page load [duplicate]

This question already has answers here:
How to make JavaScript execute after page load?
(25 answers)
Closed 1 year ago.
I am using following code to execute some statements after page load.
<script type="text/javascript">
window.onload = function () {
newInvite();
document.ag.src="b.jpg";
}
</script>
But this code does not work properly. The function is called even if some images or elements are loading. What I want is to call the function the the page is loaded completely.
this may work for you :
document.addEventListener('DOMContentLoaded', function() {
// your code here
}, false);
or
if your comfort with jquery,
$(document).ready(function(){
// your code
});
$(document).ready() fires on DOMContentLoaded, but this event is not being fired consistently among browsers. This is why jQuery will most probably implement some heavy workarounds to support all the browsers. And this will make it very difficult to "exactly" simulate the behavior using plain Javascript (but not impossible of course).
as Jeffrey Sweeney and J Torres suggested, i think its better to have a setTimeout function, before firing the function like below :
setTimeout(function(){
//your code here
}, 3000);
JavaScript
document.addEventListener('readystatechange', event => {
// When HTML/DOM elements are ready:
if (event.target.readyState === "interactive") { //does same as: ..addEventListener("DOMContentLoaded"..
alert("hi 1");
}
// When window loaded ( external resources are loaded too- `css`,`src`, etc...)
if (event.target.readyState === "complete") {
alert("hi 2");
}
});
same for jQuery:
$(document).ready(function() { //same as: $(function() {
alert("hi 1");
});
$(window).load(function() {
alert("hi 2");
});
NOTE: - Don't use the below markup ( because it overwrites other same-kind declarations ) :
document.onreadystatechange = ...
I'm little bit confuse that what you means by page load completed, "DOM Load" or "Content Load" as well? In a html page load can fire event after two type event.
DOM load: Which ensure the entire DOM tree loaded start to end. But not ensure load the reference content. Suppose you added images by the img tags, so this event ensure that all the img loaded but no the images properly loaded or not. To get this event you should write following way:
document.addEventListener('DOMContentLoaded', function() {
// your code here
}, false);
Or using jQuery:
$(document).ready(function(){
// your code
});
After DOM and Content Load: Which indicate the the DOM and Content load as well. It will ensure not only img tag it will ensure also all images or other relative content loaded. To get this event you should write following way:
window.addEventListener('load', function() {...})
Or using jQuery:
$(window).on('load', function() {
console.log('All assets are loaded')
})
If you can use jQuery, look at load. You could then set your function to run after your element finishes loading.
For example, consider a page with a simple image:
<img src="book.png" alt="Book" id="book" />
The event handler can be bound to the image:
$('#book').load(function() {
// Handler for .load() called.
});
If you need all elements on the current window to load, you can use
$(window).load(function () {
// run code
});
If you cannot use jQuery, the plain Javascript code is essentially the same amount of (if not less) code:
window.onload = function() {
// run code
};
If you wanna call a js function in your html page use onload event. The onload event occurs when the user agent finishes loading a window or all frames within a FRAMESET. This attribute may be used with BODY and FRAMESET elements.
<body onload="callFunction();">
....
</body>
You're best bet as far as I know is to use
window.addEventListener('load', function() {
console.log('All assets loaded')
});
The #1 answer of using the DOMContentLoaded event is a step backwards since the DOM will load before all assets load.
Other answers recommend setTimeout which I would strongly oppose since it is completely subjective to the client's device performance and network connection speed. If someone is on a slow network and/or has a slow cpu, a page could take several to dozens of seconds to load, thus you could not predict how much time setTimeout will need.
As for readystatechange, it fires whenever readyState changes which according to MDN will still be before the load event.
Complete
The state indicates that the load event is about to fire.
This way you can handle the both cases - if the page is already loaded or not:
document.onreadystatechange = function(){
if (document.readyState === "complete") {
myFunction();
}
else {
window.onload = function () {
myFunction();
};
};
}
you can try like this without using jquery
window.addEventListener("load", afterLoaded,false);
function afterLoaded(){
alert("after load")
}
Alternatively you can try below.
$(window).bind("load", function() {
// code here });
This works in all the case. This will trigger only when the entire page is loaded.
window.onload = () => {
// run in onload
setTimeout(() => {
// onload finished.
// and execute some code here like stat performance.
}, 10)
}
If you're already using jQuery, you could try this:
$(window).bind("load", function() {
// code here
});
I can tell you that the best answer I found is to put a "driver" script just after the </body> command. It is the easiest and, probably, more universal than some of the solutions, above.
The plan: On my page is a table. I write the page with the table out to the browser, then sort it with JS. The user can resort it by clicking column headers.
After the table is ended a </tbody> command, and the body is ended, I use the following line to invoke the sorting JS to sort the table by column 3. I got the sorting script off of the web so it is not reproduced here. For at least the next year, you can see this in operation, including the JS, at static29.ILikeTheInternet.com. Click "here" at the bottom of the page. That will bring up another page with the table and scripts. You can see it put up the data then quickly sort it. I need to speed it up a little but the basics are there now.
</tbody></body><script type='text/javascript'>sortNum(3);</script></html>
MakerMikey
I tend to use the following pattern to check for the document to complete loading. The function returns a Promise (if you need to support IE, include the polyfill) that resolves once the document completes loading. It uses setInterval underneath because a similar implementation with setTimeout could result in a very deep stack.
function getDocReadyPromise()
{
function promiseDocReady(resolve)
{
function checkDocReady()
{
if (document.readyState === "complete")
{
clearInterval(intervalDocReady);
resolve();
}
}
var intervalDocReady = setInterval(checkDocReady, 10);
}
return new Promise(promiseDocReady);
}
Of course, if you don't have to support IE:
const getDocReadyPromise = () =>
{
const promiseDocReady = (resolve) =>
{
const checkDocReady = () =>
((document.readyState === "complete") && (clearInterval(intervalDocReady) || resolve()));
let intervalDocReady = setInterval(checkDocReady, 10);
}
return new Promise(promiseDocReady);
}
With that function, you can do the following:
getDocReadyPromise().then(whatIveBeenWaitingToDo);
call a function after complete page load set time out
setTimeout(function() {
var val = $('.GridStyle tr:nth-child(2) td:nth-child(4)').text();
for(var i, j = 0; i = ddl2.options[j]; j++) {
if(i.text == val) {
ddl2.selectedIndex = i.index;
break;
}
}
}, 1000);
Try this jQuery:
$(function() {
// Handler for .ready() called.
});
Put your script after the completion of body tag...it works...

What are the pros and cons of timeouts vs counting down with a content loading asynchronous call in JavaScript / jQuery

To my way of thinking, I might be over-engineering with the recursive solution.
Wait 2 seconds for first set of modules to be loaded:
function loadContents() {
$('[data-content]:not(.loaded)').each( function() {
$(this).load($(this).data('content'));
$(this).addClass('loaded');
});
}
loadContents();
setInterval(loadContents, 2000);
When all of first set of modules are loaded, check for new modules:
function loadContents() {
var notLoaded = $('[data-content]:not(.loaded)'),
notLoadedLength = notLoaded.length;
notLoaded.each( function(i,element) {
$(element).addClass('loaded');
$(element).load($(element).data('content'), function() {
// one more has been loaded
notLoadedLength--;
if (notLoadedLength == 0) {
alert("countdown good");
loadContents();
}
});
});
}
loadContents();
You should be able to do all of this with success handlers and no polling with timers.
You don't specify exactly what you want to do, but if you want to load multiple things in parallel and know when they are all loaded, then you can just keep some sort of state on how many have been loaded and when the count shows that they are all now loaded, you will know you're done.
If you want to load them sequentially, then you can just load the next one from each success handler. It's probably easiest to create a list of things to be loaded and just have a generic success handler that gets the next one in the list and kicks off it's load and removes it from the list. When the list of remaining items to load is empty, you're done.
Edit: Looking further at your code, it looks like you're loading them all in parallel. You can just create a success handler for each one that is loading, add the loaded class in that success handler and see how many more have not yet finished. I would suggest this:
function loadContents() {
$('[data-content]:not(.loaded)').each( function() {
var obj = $(this); // save in local variable in function closure so we can reference it in the success handler
obj.load(obj.data('content'), function() {
obj.addClass('loaded');
if ($('[data-content]:not(.loaded)').length == 0) {
// all pieces of content are now loaded
} else {
// some pieces of content are still loading
}
});
});
}
loadContents();
Edit 2: OK, based on your comments, I now understand the problem better. I would scope loadContents to a parent of the DOM tree and then call it on the newly loaded content from the success handler. This will work for inifinite levels and it's safe because it only ever calls itself once for any given parent of the DOM tree. When there is no new content to load, it just has nothing to do and thus doesn't call itself any more. Here's what I would recommend:
function loadContents(root) {
$('[data-content]:not(.loaded)', root).each( function() {
var obj = $(this); // save in local variable in function closure so we can reference it in the success handler
obj.load(obj.data('content'), function() {
obj.addClass('loaded');
loadContents(obj); // now load any contents from the newly loaded content
});
});
}
loadContents(document.body); // start it off by looking in the whole DOM tree

How to tell whether the $(window).load()/window.onload event has already fired?

I have a script that is being inserted dynamically via another script. The code in that script is wrapped inside the $(window).load() event because it requires the images on the page to have all loaded. In some browsers it works fine, but in others it seems not to fire because the page has already finished loading by the time the code is run.
Is there any way to check and see whether the page has already finished loading - either via jQuery or JavaScript? (including images)
In this situation, I don't have access to the onload event of the original document (aside from altering it via the loaded script - but that would seem to present the same problem).
Any ideas/solutions/advice would be greatly appreciated!
You could try setting up a handler that's invoked via a timeout that will check the images to see if their properties are available. Clear the timer in the load event handler so if the load event occurs first, the timer won't fire. If the properties aren't available, then the load event hasn't fired yet and you know that your handler will eventually be invoked. If they are, then you know that the load event occurred before your handler was set and you can simply proceed.
Pseudocode
var timer = null;
$(function() {
$(window).load( function() {
if (timer) {
clearTimeout(timer);
timer = null;
}
process();
});
timer = setTimeout( function() {
if (checkAvailable())
process();
}
}, 10*1000 ); // waits 10 seconds before checking
});
function checkAvailable()
{
var available = true;
$('img').each( function() {
try {
if (this.height == 0) {
available = false;
return false;
}
}
catch (e) {
available = false;
return false;
}
});
return available;
}
function process() {
... do the real work here
}
I wrote a plugin that may be of some use: http://plugins.jquery.com/project/window-loaded
I think your problem would resolve itself if you'd use $(document).ready instead of $(window).load - see the jquery documentation.
You guys should read this:
http://web.enavu.com/daily-tip/daily-tip-difference-between-document-ready-and-window-load-in-jquery/
Don't know if this is what you are after, but have you tried(?):
$(document).ready(function(){
...
});
http://docs.jquery.com/Events/ready#fn

Categories

Resources