I want to load my javascript files after the page is loaded and make sure that they are being cached.
This question has been asked and answered a lot but they all suggest loading it with jQuery ($.getScript) while one of the files I want to load is the jQuery itself and I can not use jQuery. there are some options like:
(function(){
var newscript = document.createElement('script');
newscript.type = 'text/javascript';
newscript.async = false; //as I'm going to execute some functions
//after this I want to make sure that the
//script is fully loaded
newscript.src = 'https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js';
(document.getElementsByTagName('head')[0]||document.getElementsByTagName('body')[0]).appendChild(newscript);
})();
but I'm not sure if they are cached or not.
and Is there a way to fire an event when dynamically loading script is done?
You can easily check if they are cached by loading your page for a second time with the network tab of the developer tools of your browser opened. You can tell by the way the scripts are loaded whether the file is cached or not.
They should be, by the way. You're basically inserting a script tag through JavaScript, after which the script is loaded as it would be if the tag was already in the page.
If you make it load asynchronously, you can attach an onload event to a script tag, which will fire as soon as the script is loaded. This should work in any modern browser, including IE9+ in standard mode. If you need support for IE8, you will have to do some extra work, which is what $.getScript() also does. An in-depth discussion of that jQuery functionality, with alternative code snippets can be found in the question 'onload' handler for script tag in Internet Explorer.
Related
I have some confusion around the new async attribute to the script element in HTML5 that I hope someone can give a clear answer to.
Browsers are capable of Parallel Connections, therefore images will be downloaded in parallel. But any external javascript is not downloaded in parallel with other external javascript and images. Scripts block page loading until they have been downloaded and executed.
To download a script without blocking the rest of the page loading, the most common technique is to create a script element, like Google Analytics snippet does:
var ga = document.createElement('script');
ga.type = 'text/javascript';
ga.src = '...ga.js';
ga.async = true;
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
I'm not sure of how that works exactly -
either
the browser parses and renders the page, then once it has finished it notices the DOM has changed, resulting in the ga.js script being downloaded and executed
or
the browser starts downloading the javascript in parallel with other resources.
I think it is the latter.
The new asynchronous Google Analytics snippet includes the HTML5 async attribute in the script element it creates. That will not help the page blocking problem - that has already been solved by the "Script DOM Element" technique. So what does async add to the picture? According to w3schools, "if async is present, the script is executed asynchronously with the rest of the page (the script will be executed while the page continues the parsing)".
And according to Steve Souders site, "the main benefit of this [async attribute] is it tells the browser that subsequent scripts can be executed immediately – they don’t have to wait for ga.js".
So are async and the Script DOM element technique both solving the same problem?
Will work:
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script>$('body').append('Yey');</script>
Will not work:
<script async src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script>$('body').append('Yey');</script>
The async attribute is just a clearer (no ambiguity very straightforward) and cleaner (it will, or is already, part of the respected HTML5 specification) approach to solve the problem. If your site serves scripts from another domain (or CDN) then the async attribute gives you a little reliability (allow the user to at least read the static content) in that the page won't block while a script from a slow (possibly down) remote host is trying to load.
There was a great article from Jake Archibald on html5rocks which addresses this topic.
According to https://www.html5rocks.com/en/tutorials/speed/script-loading/ if a <script> element is added dynamically it may not be executed until DOMContentLoaded is fired. That is, some user agents (e.g. MSIE 10) will wait until DOM is ready before running dynamically added <script> elements.
I guess Google wants to get their analytics code running faster on those user agents and as such they need to add async flag to tell the browser (e.g. MSIE 10) that it's okay to start executing the script as soon as possible. HTML5 compatible browsers would execute as if the async true even if it was not defined so the async=true has been added only to improve performance with non-HTML5 browsers.
setting async attribute to true makes sure that the script is loaded along with the rendering of html in parallel.This is essential because if script is placed at end of body and in html we are using something that depends on javascript code,so it won't be loaded and creates issue
defer can be used but defer just pauses execution of script and renders html
Async scripts are executed as soon as the script is loaded, so it doesn't guarantee the order of execution (a script you included at the end may execute before the first script file )
Defer scripts guarantees the order of execution in which they appear in the page.
This is probably a very simple issue, but I've been trying to use Firebase in an external javascript file that is being used with an HTML file and can't get it to work properly. I am planning to use this file for many other similar pages, so I'd rather keep it in an external document. Specifically, my code is:
$(function() {
var head= document.getElementsByTagName('head')[0];
var script= document.createElement('script');
script.src= 'https://cdn.firebase.com/v0/firebase.js';
head.appendChild(script);
var Database = new Firebase('https://myfirebase.firebaseIO.com/');
...
but when I try to run it, it says that the Firebase object/keyword is undefined. I know that the script is being correctly appended to the HTML page because I've checked the HTML on the page after running the code.
I have also read somewhere that you might need to have a personal server to run Firebase, but frankly I don't really know what that means - in any case, I use Mac OSX and run all of my HTML and Javascript in Chrome.
Thank you very much!
The problem is that using document.createElement does not force the script to be loaded and rendered before your inclusive script is invoked (it's being invoked now). There are no guarantees by this method on when the script you include will get invoked.
Additionally, you are loading the script onDomReady by putting it inside $(function() {...}); you would want to insert it into the header immediately, not wait for the entire document to load.
The simplest answer is to just put Firebase into the head of the html page; you haven't really explained your limitations here, but I assume this isn't an option for you. If it is, KISS.
Another simple answer is to utilize jQuery, since you obviously have it available.
$.getScript('https://cdn.firebase.com/v0/firebase.js', function() {
// now I can use Firebase
});
You can also accomplish this with other methods (wait until Firebase is defined using a setInterval; utilize other script retrieval methods besides document.createElement--try googling "load scripts dynamically via javascript load order"), but I think this covers your needs sufficiently.
I want to load a non-blocking javascript on my page. Before async is supported, the best practice seems to dynamically load it via a simple script.
Here is an example that works fine in which it is inserted before the first <script>:
var myscript = document.createElement('script');
myscript.async = true; // cannot hurt, right?
myscript.type = 'text/javascript';
myscript.src = 'myscript.js';
var node = document.getElementsByTagName('script')[0];
node.parentNode.insertBefore(myscript, node);
I found several versions inserting the script in different places like the end of <head> or the <body>:
document.getElementsByTagName("head")[0].appendChild(myscript);
document.getElementsByTagName("body")[0].appendChild(myscript);
The order seems to matter in some browsers though it is asynchronous.
Are there any difference in terms of browser support? performance? blocking risk?
I don't have any constraint in terms of order (they don't impact each other) but I want to make sure that if my script takes too long to load the page content will still load just fine. I would think the last solution works best but I am not sure of the differences.
You'll want to use something like $script.js: http://www.dustindiaz.com/scriptjs
Appending the scripts at the end of the body is the best solution here. It still allows for loading the DOM without blocking for the script tags. Also if you put your scripts at the end of the document you no longer need to wrap your functions in a DOM ready event because at the moment your scripts start executing the DOM will already be loaded by the browser and you could directly start manipulating it or subscribing to some events.
You could try having a script that waits for the page to be complete and then loads the script that you want to add. Have done this recently and the page loads fine and then a new block appears.
var Widget = {}
Widget.myDocReadyInterval = setInterval(function(){
if (document.readyState === "complete")
{
clearInterval(Widget.myDocReadyInterval);
Widget.startLoading();
}
}, 20);
Widget.startLoading(){
// do what you need here...
}
Your question focuses on the load part, but actually performance can be impacted by different phases:
load
parsing
execution
For this reason adding the script at the end of the body is usually considered the less obtrusive.
To push it even further, you could wait for DOM ready to run your load script. In this case, it won't matter whether you attach the script to the head or the body.
[Edit] Side comment: the head and body tags are not mandatory in html pages. document.getElementsByTagName('script')[0] is a good approach in such edge cases as it guarantees that you'll get an element (there's at least your load script in the page).
I have included 3 external js files at the end of body.
Suppose my document already contains a js named as insertlibs.js and here is the code
var script1 = document.createElement('script');
script1.src='http://code.jquery.com/jquery-latest.js';
script1.type='text/javascript';
document.getElementsByTagName('Body').item(0).appendChild(script1);
// Similar way to include underscore
var script2 = document.createElement('script');
script2.src='hhttp://documentcloud.github.com/backbone/backbone-min.js';
script2.type='text/javascript';
document.getElementsByTagName('Body').item(0).appendChild(script2);
But what is happening sometimes, it is throwing an error that $ is not defined and I tried to debug in Firefox and there is a parallel download occurring for jquery and backbone and sometimes backbone library getting download earlier than jQuery which is causing this error.
As far as i know that if a script tag is included, it will block further request So as soon as I add jquery in dom. I am confused about the workflow here happening.
So i have found the solution, I merged both the js and making a single call which is working perfectly but that does not explain me the flow happening in above case. Please help.
This is because you are attempting to include backbone without ensuring that jquery has been completely loaded. To correct this, you can use the script's onload attribute to attach a callback which will be fired when jquery is loaded.
For ex:
var script1 = document.createElement('script');
script1.src='http://code.jquery.com/jquery-latest.js';
script1.type='text/javascript';
// add an onload handler
script1.onload = function() {
// load the rest of the scripts here
var script2 = document.createElement('script');
script2.src='hhttp://documentcloud.github.com/backbone/backbone-min.js';
script2.type='text/javascript';
document.getElementsByTagName('Body').item(0).appendChild(script2);
}
document.getElementsByTagName('Body').item(0).appendChild(script1);
As far as i know that if a script tag is included, it will block further request
No, the blocking / synchronous download is only when the tags are right in the parsed HTML (or are inserted via document.write during the parse); dynamically DOM-appended scripts load asynchronously and in parallel.
To do that but ensure that scripts are executed when their dependencies are met, you need to use AMD loaders.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
jquery - Is $(document).ready necessary?
Putting the JS just above the </body> tag improves perceived load time because the browser doesn't have to read and parse through all the JS before it can start rendering the page.
But it has another benefit, doesn't it? We don't need to wrap the JS in $(document).ready(function() { ... }) because all the elements are already above the JS and thus are ready for manipulation.
Is $(document).ready necessary to ensure the DOM has fully loaded and is ready for manipulation?
Is there any difference between the execution times? Would one method fire faster than the other?
Could we link our external JS files (<script src="..." />) at the bottom of the page too then, or does that need to be in the header?
This SO answer says NO:
stackoveflow question
$(document).ready is for assurance full DOM is available at the time the function is called.
Any functions and events not depending on the DOM don't need to be put into the ready event.
Also - to improve page rendering speed - load javascript files dynamically in non-blocking fashion: http://berklee.github.com/nbl/ or https://github.com/rgrove/lazyload/
This technique works somewhat like this:
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "file1.js";
document.getElementsByTagName("head")[0].appendChild(script);
This new element loads the source file file1.js. The file begins downloading as soon as the element is added to the page. The important thing about this technique is that the file is downloaded and executed without blocking other page processes, regardless of where the download is initiated. You can even place this code in the header of a document without affecting the rest of the page (aside from the one HTTP connection that is used to download the file).
this book: "High Performance JavaScript" by Nickolas Zakas has a lot of interesting information about JavaScript performace optimization.