What to use in place of $(document).ready();? - javascript

So I'm using jquery along with some plugins I wrote.
I do all the initialization in a $(document).ready(function(){}) block however this is executed when the whole DOM has been loaded and is ready to be used.
However that would take long eg. when there is a server load. Or maybe the user clicks a button that has been loaded while the rest of the page hasn't loaded yet (and thus document.ready() hasn't been executed yet) in which case it would do nothing.
So, what if I want a code to be executed right after the related part of the page has been loaded instead of waiting for the WHOLE page to be loaded?
I know placing inline code right after the html that this js operates on would do the trick but what if that code uses a library like jQuery that hasn't been loaded yet?

I know placing inline code right after the html that this js operates on would do the trick but what if that code uses a library like jQuery that hasn't been loaded yet?
That would be the only way. The HTML is parsed from top to bottom. So you can expect every script you included to be accesible after you included it.

Your page should still work without JavaScript anyway, so a user clicking a button extremely fast will just temporarily have a somewhat degraded experience.
That being said, the DOM is basically ready when the HTML document all scripts are loaded. Since you cannot execute meaningful JavaScript before the JavaScript code is loaded (duh), I'd have a close look at page performance. Sending an HTML document and 2,3 JavaScript files should not be slow.
You could also use the old-style inline event handlers, like <button onclick="registerButtonClickEvent()">. However, this would introduce a complex, potentially buggy and hardly testable layer of temporary event holding.

If your <script src="jquery-whatever.js> line precedes the first clickable element in your HTML, it is guaranteed that the jquery library will be loaded and run before the user has anything useful to click on.
Just don't add async or defer attributes to the script element.

The onload event isn't triggered from all html elements, so you're forced to wait for window load. It doesn't matter where you load jQuery since it will have to wait for document to be ready. That total time required to load jQuery plus the rest of the document will be thet same.

Related

Looking for an alternative to $(window).load that is slower than $(document).ready

I am trying to hide my preloader with JavaScript once the DOM and at least the top content has been loaded. The problem is that my page has several iframes which can slow the process down a lot.
My understanding is that if I use jQuery's $(document).ready to hide the preloader, it will be hidden too soon. On the other hand, if I use $(window).load, the waiting time may be too long. So, is there a middle-way solution, - kind of like window.load but without waiting for iframes?
EDIT:
My page has stuff like Facebook Like button Google Translate and a few other scripts that work via iframes. These are not critical elements, and I would not like to wait for them to load fully.
On the other hand, CSS files like Bootstrap, jQuery, etc. are curcially important for the presentation, and therefore to show the page (hide preloader) w/o having these loaded first would be premature.
Thanks.
You could use $(document).ready to determine if a particular element is loaded before hiding your loader.
Or if you have partial views, to have a $(document).ready function in one of those pages js do the loader hide job.
Since you did not provide more info, these are closer to guesses than real solutions.
I think you're looking for document.onload, which will fire when the DOM tree is ready. I believe that it fires before iframes, which all get their own onload callback/event handler.
You can also try placing the script tag at the end of your html file without begin inside an onload or ready function. This will cause it to load the html content, then fire the Javascript.
EDIT
A thought just occurred to me, which may or may not be useful. You probably have an idea about when you want your script to execute. In whatever browser you are using, check the network tab of the development console. There may be some other element's onload function you want to wrap your code in. For example, if you have a background image you want to make sure loads before your code executes, you may want to use it's onload.
As Petre said, lack of info in the question makes answering difficult.

Order of DOM Execution Issue

I have some JavaScript in the HEAD tag that dynamically inserts an asynchronously loading script tag before the last script on the page (that has been currently parsed). This dynamically included script tag contains JavaScript that needs to parse the DOM after the DOM is available, but before all images AND script tags have been loaded in. It's important that the JavaScript starts executing before all JS has been loaded in, because if there is a hanging script, this would lead to a bad user experience. This means I can't wait for the DOMContentLoaded event to fire. I don't have any flexibility as to where I place the first bit of JavaScript that is dynamically including the script tag.
My question is, is it safe for me to start parsing through the DOM right away, without waiting for the DOMContentLoaded event? If not, is there a way for me to do this without waiting for the DOMContentLoaded event?
...JavaScript in the HEAD ... dynamically inserts an asynchronously loading script tag before the last script on the page...
I'm assuming the loader script is inline, meaning that the highlighted bit actually refers to the "current" script element i.e. the loader. This happens since only the html preceding the loader script tag has been parsed and interpreted, so the inserted script tag is actually still in the head and not at the bottom of the page. So the target script is limited to performing DOM operations on preceding elements only, unless you wrap the code into a DOM ready callback... which is what you're trying to avoid in the first place!
Basically you want to load all html so that the page is visible/scannable, start loading images/stylesheets (which occurs in non-blocking threads) and then load any javascript. One approach is to put your target script at the bottom of the page, just pick their order correctly (interactivity first, enhancements second, third party analytics/social media integration/anything else super-heavy last) and adjust for your needs. Technically it still blocks the page load, but there are only scripts left at the bottom of the page anyway (and since they are at the bottom, you would be able to directly manipulate DOM as soon as they're loaded, minus some IE7 quirks).
There is a relevant rant/overview I like to link to that provides decent examples and some timing trivia on use and abuse of DOM ready callbacks, as well as the "other side of the story" on why stellar performance could be of lower value than a sane dependency management framework. The subject of latter is far too broad to be exhausted in one answer, but something like requirejs documentation should give you a fair idea of how the pattern works.
Perhaps another pattern for to consider is building an SPA - single page application which leverages asynchronous access to content chunks rather than the "traditional" navigating between complete pages. The pattern comes with an underestimated but rather significant performance benefit from not having to parse and re-execute shared javascript on every page, which would also address your (valid) concern about third-party js performance. After all, just a good caching policy would do wonders for loading time, but poor javascript code or massive frameworks' execution overhead remains.
Update: Figured this out. With your specific scenario in mind (i.e. no control over markup per se, and wanting to be the last script to execute), you should wrap the insertion of the async script element into DOM into a 0ms setTimeout callback:
setTimeout(function(){
//the rest is how GA operates
var targetScript = document.createElement('script');
targetScript.type = 'text/javascript';
targetScript.async = true;
targetScript.src = 'target.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(targetScript, s);
}, 0);
Due to the single-threaded nature of the environment, js setTimeout callback is basically added to a queue for 0ms-delayed execution as soon as the thread is no longer busy (more thorough explanation here). So the browser isn't even aware of the need to load, let alone execute, the target script until after all "higher priority" code has been completed! And since DOM is operational when the script tag is being added, you will not have to check for it explicitly in the target script itself (which is handy for when it's loaded "instantly" from cache).
The behavior of the following techniques make it safe to parse DOM ...
Using window load or DomContentLoaded event
Declare or inject your script at the bottom of the page
Place "async" attribute on your script tag
or doing this:
<script>
setTimeout(function(){
// script declared inside here will execute after the DOM is parsed
},0);
</script>
Also, these will NOT BLOCK the page loading in DOM.
There is no need to call the DomContentLoaded event when declaring script below any DOM you are depending on UNLESS you are needing to do size calculations or positioning as images/video will change the sizing of things if width/height is not specified.
Here is some scenarios where this works.
DEPENDENT DOM IS ABOVE
<script src="jquery.js"></script>
<script>
$('mydom').slideDown('fast');
</script>
or try this:
<script>
// won't fart
setTimeout(function(){ console.log(document.getElementById('mydom').innerHTML); },0);
</script>
DEPENDENT DOM IS BELOW or ABOVE (dont' matter)
Here's my little test for you to see setTimeout working as its one of those strange things I didn't notice until recently so its nice to see a working example of it.
http://jsfiddle.net/FFLL2/
Yes, you should wait for the user agent to tell you that the DOM is loaded.
However, there is more than one way to do so.
There is a difference between onreadystatechange to interactive and DOMContentLoaded.
According http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html
the first thing the user agent does, after stopping parsing the document, is setting the
document readiness to "interactive".
The user agent does not wait for scripts to be loaded.
When the document readiness changes, the user agent will fire readystatechange at the Document object.
So if the scripts you are worrying about are non-inline, you might hook up with readystatechange.
Talking about cross-browser: This is the spec.
I strongly advise you to fully read the following article which delves in detail into mysteries of script loading and actual DOM readiness and when is it safe to do what with what, also taking into account browser disrepancies.
http://www.html5rocks.com/en/tutorials/speed/script-loading/

What event does JQuery $function() fire on?

We have a JQuery $(function() statement as:
<script type="text/javascript">
$(function(){
//Code..
})
</script>
Dumb question - when exactly is this function executed? Is it when the entire HTML page has been downloaded by the client?
What is benefit of using the wrapping your code within $(function() as opposed to just doing:
<script type="text/javascript">
//Code..
</script>
It fires when the document has been parsed and is ready, and is the equivalent of $(document).ready(function () { }).
The obvious benefit is that having your script tag before other elements on the page means that your script can interact with them even though they're not available at parse time. If you run your script before elements have been parsed and the document is not ready, they will not be available for interaction.
It is executed as soon as the DOM is parsed and is invoked in order of appearance if there are multiple appearances. At this point the document is however not displayed, its just parsed.
When the document completes loading. It is the same as writing this:
$(document).ready(function(){});
EDIT: To answer your second question:
If you don't wrap your code in the block above then it would fire as soon as it is encountered instead of after all the controls on the page have loaded. So if a block was at the top of a page and it referred to elements in the page those references would not work as the elements have not loaded yet.
But if you wrap in the block then you know that the page has loaded and all elements are available to now reference.
It fires after the the document has fully loaded, the DOM tree has been initialized, all CSS styles have been applied and all Javascript has been executed. It differs from the load event in that elements (other than CSS/JS) that load their content from other URLs, such as images or flash files, have not necessarily finished loading at this point. This is usually called the "domready" or "domloaded" event, and some modern browsers support it directly (e.g. Firefox has a DomContentLoaded event), and on others it can be simulated with various tricks, like using the defer attribute or placing a script at the very end of the body.
The advantage is that you can reliably interact with the document at this time; for example you can set an event handler on an element with a certain ID and be sure that it already exists in the DOM tree. On the other hand, it can run considerably earlier than the load event, if some external resource is slow to load. If your script is at the end of your HTML code, then there might be little difference in using or not using the domready event, but usually scripts are called from the head tag, and at that point no elements of the body are available yet.

If Javascript code block is not at end of HTML file, but is using jQuery's $(document).ready(function() {...}), will it slow down the page display?

It is said that Javascript code should be all placed at the end of HTML file, so that the page content is shown first, for the user to see something (so that the user is satisfied to see something instead of waiting another 12 seconds, for example).
But to better encapsulation of the HTML and match Javascript code, such as an "Image Carousel", then usually the HTML and Javascript is placed in one single file, so there are Javascript code blocks all intermixed with HTML code throughout the final HTML file.
But what if all these Javascript code blocks use jQuery's $(document).ready(function() { ... }) to perform the task, then won't the page display be very fast as well? I think not as fast as when the Javascript is actually placed at the end of the HTML file, but close enough, because it merely adds a function to the ready event queue.
I think the point is to place the js at the bottom of the page (usually just inside the closing </body> tag) so that the content of the page is displayed while the js is downloading.
If you have your jQuery code spread out throughout the HTML in separate .ready() calls, then no matter what, it won't run until the <body> has fully loaded. So the question would be how much javascript do you have in the HTML?
If there's quite a bit, then it will slow down the display of any content that comes after each script. If it is a relatively small amount of code, then it won't likely make much noticeable difference.
If it is really important to you to have the page's content displayed as soon as possible, then place all scripts after the content.
I personally wouldn't mix javascript with HTML just for the sake of association. You could have unexpected results if you start removing/appending content that happens to include a script. I'd rather use appropriately named classes and IDs, as well as lots of code comments.
Also keep in mind that those .ready() calls won't work until jQuery has loaded, which would mean that it would need to be at the top of the page, or at least before your first call.
So again it gets back to the question of which is more important to you. If you want the content visible as quickly as possible, place all js at the bottom. If you want your method of intermixing js and HTML, you'll have some delay in displaying the page.

Move jQuery to the end of body tag?

My friend read an article which mentioned that moving all JavaScript files to the end of the closing body tag (</body>), will improve the performance of a web page.
I have moved all JS files to the end except the JQuery and the JS files which are attaching event to an element on page, like below;
$(document).ready(function(){
//submit data
$("#create_video").click(function(){ //... });
});
but he's saying to move the jQuery library file to the end of body tag.
I don't think it is possible, because I am attaching many events to page elements on load using jQuery selectors, and to use jQuery selectors it is must to load jQuery library first.
Is it possible to move JQuery library file to the end of page right before closing body tag (</body>) ??
Thanks
It's standard practice to move all your js includes to the bottom of your page. This is because when a browser loads script, it does not spawn a new thread to do so, so basically the browser will wait until it has loaded the script before it proceeds to the next line.
What this means for your users is that they will see a blank screen. Much better to have them see the full(ish) page as then it doesn't look like it has stalled.
The $(document).ready function says not to run until the DOM has finished being instantiated - so moving it to after body is okay so long as the JQuery library is loaded first. Unconventional and some assumptions may not be correct anymore but okay.
Just take in account that the jQuery JavaScript file must be loaded before any call to the $(...) function.
Use a "Dom Ready Queue" to collect functions to be executed once jQuery is loaded and the DOM is ready.
Example:
<html>
<head>
<script type="text/javascript">
var domReadyQueue = [];
</script>
</head>
<body>
...
<div class="foo"></div>
<script type="text/javascript">
domReadyQueue.push(function($){
$('.foo').doSomething();
})
</script>
...
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script type="text/javascript">
jQuery(function(){
while (domReadyQueue.length) {
domReadyQueue.shift()(jQuery);
}
});
</script>
</body>
</html>
The reason that article asked you to move scripts to the bottom, is to allow other artifacts to get downloaded first. (css & images, which will speed up apparent rendering times)
This is because HTTP 1.1 recommends only downloading 2 items per hostname. And you would definitely want your css file to be one of the first files downloaded, rather than javascript which could make the site appear to render slower (just by the fact that the browser hasn't got the css file yet and isn't sure what it should do with the html)
But if you used google to host your jQuery then that would download in parallel and negates any reason for moving it to the bottom of your pages.
Alternatively, you could set up a second hostname to host static content (such as css/scripts/images).
But google have already done the hard work for you, so it makes sense to use it if it suits. :-)
Q - Why do I often see JavaScript
written/included before the closing
body element in an (x)HTML document?
A - DOM elements can not be accessed
by JavaScript until the browser has
loaded the HTML elements into the DOM.
By placing JavaScript at the end of an
(x)HTML document (before the closing
body element), you will ensure that
the script is called as soon as the
DOM is constructed/loaded and ready
for manipulation. An advantage of this
approach is that JavaScript code is
executed right after the DOM is
constructed and possibly before the
onload event would fire.
JavaScript beginners get tripped up by
this constantly by placing code that
manipulates the DOM in the header
element of an (x)HTML document. This
causes an error because the DOM has
not yet been constructed and thus is
not yet accessible to JavaScript that
traverses/manipulates the DOM.
From JavaScript Execution & Onload Techniques in Web Browsers
Use unobtrusive javascript (adding event listeners to elements instead of onclik ="..." etc).
Put all your .js files at the bottom of the body tag, with the main library (jQuery in this case) placed first, and everything will be fine. You can use a bundler like bundle fu
You will see a big performance boost of loading your page.

Categories

Resources