I use this code to load my JS async in the head
<script type='text/javascript'>
// Add a script element as a child of the body
function downloadJSAtOnload() {
var element4= document.createElement("script");
var element5= document.createElement("script");
element4.src="http:///ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"
element5.src="http://yourjavascript.com/301810712121/slidemenu_horiz.js"
element4.async=true;
element5.async=true;
document.body.appendChild(element4);
document.body.appendChild(element5);
}
// Check for browser support of event handling capability
if (window.addEventListener)
window.addEventListener("load", downloadJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent("onload", downloadJSAtOnload);
else window.onload = downloadJSAtOnload;
</script>
In IE and Firefox works fine, but in Chrome I have this error:
"Uncaught ReferenceError: jQuery is not defined "
When I refresh the page for second time (or third) the script works fine in Chrome, please I need to know how to resolve this.
Given your needs, and because I've used it successfully in the past I'd suggest using LABjs - http://labjs.com/
As mentioned, there are loads of script loaders to choose from - LABjs is focused on performance more than anything and doesn't include many of the extra features that others such as requirejs (AMD loader), YepNope (feature detection-based conditional loader) have. If all you need is to load your scripts asynchronously and have control over the execution order, LABjs is a very small script that handles this well.
Using LABjs, you'd do the following to replicate your code above:
<script src="js/libs/LAB.js"></script>
<script>
$LAB
.script('http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js').wait()
.script('http://yourjavascript.com/301810712121/slidemenu_horiz.js')
.wait(function () {
// Check jQuery has loaded (could do this for the slider as well)
if (window.jQuery) {
// Do something with your slider
}
});
</script>
In the example above, the .wait() function ensures that jQuery has executed before slidemenu_horiz.js - the last .wait() is passed an anonymous function as a callback - within this you can test that everything has loaded and then do your initialisations.
It's worth checking out all the options as far a script loaders go. There really are loads out there and each has a different feature set that you may find addresses your problem better.
EDIT: Added script reference to LABjs in code example for clarity
Related
Is the DOM always ready when my external scripts have finished loading?
<head>
<script type="text/javascript" src="base.js"></script>
</head>
Inside base.js, I have an object that loads external scripts. It uses the following method to do so:
var head = document.getElementsByTagName("head")[0],
scriptElement = document.createElement("script");
scriptElement.type = "text/javascript";
scriptElement.onreadystatechange = function () {
if (this.readyState === "complete") onModuleLoaded();
};
scriptElement.onload = onModuleLoaded;
scriptElement.src = "externalScript.js";
head.appendChild(scriptElement);
Now, when all external scripts have been loaded, a callback function is called. My question is: Is this callback function suitable to place the
rest of my javascript code in? This code needs the DOM to be ready.
My scripts also use jQuery. But I don't think I can use
$(document).ready(function () { ... });
because in my tests that fires before my scripts have been loaded. However, I do not know if this will always be the case. If it will, my callback function is suitable for my DOM-manupilating javascript code.
But if it is possible that my scripts can be loaded before the DOM is ready to be manipulated, I need to find another way.
Thank you for reading!
Check jQuery.holdReady(). If you will try to load external js via getScript then you can easily do that.
Delay the ready event until a custom plugin has loaded:
$.holdReady( true );
$.getScript( "externalScript.js", function() {
$.holdReady( false );
});
Is the DOM always ready when my external scripts have finished loading?
Probably, yes. No.
Dynamically-added script elements load their scripts asynchronously. You're quite correct that you can't use jQuery's ready callback because it looks at when the DOM defined by the main HTML is fully loaded, which may well be before your additional scripts have loaded.
I'd be really, really surprised if the main DOM weren't loaded before your onModuleLoaded callback was called. So probably, yes, it'll be ready. Color me surprised. I ran the experiment, and guess what? It's possible for the script load and callback to happen before the rest of the page has been processed. (This is why I test my assumptions.)
But if you're worried there may be edge cases around it, you could always use ready within your callback. If jQuery has already fired the ready callbacks and you hook another one, jQuery calls it right away.
I have a small mobile page with a few big js files (including jQuery)
The page speed is pretty slow and the google page speed analysis suggests to move the 'render-blocking javascript below the fold'. My page is pretty small to begin with, so everything on it is already above the fold.
I would normally async the javascript, but the javascript needs to run in order
(First jQuery, then the plugin, and finally my own code which is inline)
So async loading on the code would cause it to run out of order, usually jquery loading last and everything else breaking before hand.
Is there an easy way to push everything below the fold? or at least make the browser treat the javascript like it is below the fold all while loading everything in order?
If all of your content is above the fold you should be able to simply put all of your javascript files towards the bottom of your document and above your closing </body> tag.
I ended up fixing the problem by wrapping the code in a callback after the page loads. Here is the code that I used:
function appendScript(src, callback) {
callback = callback || function(){};
var element = document.createElement("script");
element.src = src;
element.async = false;
element.onload = callback;
document.body.appendChild(element);
}
function downloadJSAtOnload() {
appendScript("http://code.jquery.com/jquery-1.11.1.min.js", function(){
appendScript("http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js", doStuff);
});
}
if (window.addEventListener)
window.addEventListener("load", downloadJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent("onload", downloadJSAtOnload);
else window.onload = downloadJSAtOnload;
doStuff(){
// MY CODE HERE
}
I forgot to mention in my question that the code embedded on the page isn't much at all. It is just a few snippets but would be much harder without jquery.
I hope this helps out anyone else who is trying what I tried to do
I'm encountering a strange issue. I am developing a books application and using javascript onload. I read somewhere that its best to include your javascript at the end of the html. This works for most of the html loaded. However some complain that onload init() not found. This gets solved if i include the javascript in the html head. But than other htmls start behaving strangely. onload gets called before the page is fully loaded. i dont get the correct scroll width. Please suggest what could be worng. Whats the best way of including javascripts. Thanks
html is as follows
columizer id use css column-width which i've defined like this.
css style below
#columnizer
{
width:290px;
height:450px;
column-width:290px;
column-gap:10px;
word-wrap:break-word;
}
Javascript onload is defined like this.
function init()
{
docScrollWidth = document.getElementById('columnizer').scrollWidth;
document.getElementsByTagName('body')[0].style.width = docScrollWidth + "px";
window.external.notify(str);
}
Since the actual answer was in my comment, I'll add that to my answer:
My guess is that you're doing something like window.onload = init(); instead of window.onload = init; and the init function will have to be declared before you do that assignment. You assign function references without the parens. Using the parens causes it to get executed immediately.
You say you're using this code:
docScrollWidth = document.getElementsByTagName('body')[0].style.width
The main problem with this is that style.width ONLY reads a style attribute set directly on the body object. It doesn't get the width of the object as calculated by layout or CSS rules.
So, what you should use instead really depends upon what you're trying to do. The body width will nearly always be the same or more than the window width unless your content is entirely fixed width. So, that makes me wonder what you're trying to accomplish here? What you should use instead depends upon what you're really trying to do.
FYI, document.body is a direct reference to the body object so you don't need document.getElementsByTagName('body')[0].
First, let me define the problem. The window.onload event is used by programmers to kick-start their web applications. This could be something trivial like animating a menu or something complex like initialising a mail application. The problem is that the onload event fires after all page content has loaded (including images and other binary content). If your page includes lots of images then you may see a noticeable lag before the page becomes active. What we want is a way to determine when the DOM has fully loaded without waiting for all those pesky images to load also.
Mozilla provides an (undocumented) event tailor-made for this: DOMContentLoaded. The following code will do exactly what we want on Mozilla platforms:
// for Mozilla browsers
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", init, false);
}
So what about Internet Explorer?
IE supports a very handy (but non-standard) attribute for the tag: defer. The presence of this attribute will instruct IE to defer the loading of a script until after the DOM has loaded. This only works for external scripts however. Another important thing to note is that this attribute cannot be set using script. That means you cannot create a script using DOM methods and set the defer attribute – it will be ignored.
Using the handy defer attribute we can create a mini-script that calls our onload handler:
<script defer src="ie_onload.js" type="text/javascript"></script>
The contents of this external script would be a single line of code to call our onload event handler:
init();
There is a small problem with this approach. Other browsers will ignore the defer attribute and load the script immediately. There are several ways round this. My preferred method is to use conditional comments to hide the deferred script from other browsers:
<!--[if IE]><script defer src="ie_onload.js"></script><![endif]-->
IE also supports conditional compilation. The following code is the JavaScript equivalent of the above HTML:
// for Internet Explorer
/*#cc_on #*/
/*#if (#_win32)
document.write("<script defer src=ie_onload.js><\/script>");
/*#end #*/
So far so good? We now need to support the remaining browsers. We have only one choice – the standard window.onload event:
// for other browsers
window.onload = init;
There is one remaining problem (who said this would be easy?). Because we are trapping the onload event for the remaining browsers we will be calling the init function twice for IE and Mozilla. To get around this we should flag the function so that it is executed only once. So our init method will look something like this:
function init() {
// quit if this function has already been called
if (arguments.callee.done) return;
// flag this function so we don't do the same thing twice
arguments.callee.done = true;
// do stuff
};
I’ve provided a sample page that demonstrates this technique.
Can you confirm my understanding of HTML5's <script async> attribute?
Any libraries referenced by other code in the page should not specify the async attribute.
For example, my script references might appropriately look like:
<script src="jquery..." /> <!-- async not used - ensure that this is loaded before JQuery UI and my code -->
<script src="jquery.ui..." /> <!-- async not used - ensure that this is loaded before my code -->
<script src="my_code1.js" async /> <!-- async used, for page load performance -->
<script src="my_code2.js" async /> <!-- async used, for page load performance -->
For any code in a $(document).ready(function () { } block, I can be assured that all async script have already loaded.
Do I have this right?
As with all new HTML5 features, I think the best way to find answers is to test them on as many current browsers as we can. As a general rule, old browsers should completely ignore the async flag, so code should work as expected, parsed from top to bottom in order.
As long as browsers are inconsistent in handling them, you should avoid using them in production code if you're not sure they will work.
The main question with this feature is, browsers that do support it, in what order do events get fired, for example if you define a jQuery ready function in an async loaded script, is it going to get fired? Does your ready event fire before or after async scripts have loaded?
I have created a couple of test files, you are quite welcome to have a play with them on different browsers to see how they behave.
Short Answer
About #Dave's assumption:
For any code in a $(document).ready(function(){} block, I can be assured that all async script have already loaded.
It doesn't look like it so far, it's pretty inconsistent. In Chrome the main ready event fires before the async file has loaded, but in Firefox it fires after it.
jQuery developers will have to make up their minds about this, if they will (and can) support it in the future or not.
Test Page
My test script spits out a string which shows you in what order were different parts of it executed. It can be built by the following:
D: It means the script block in the main file got executed. It can be
followed by :ok if the function in
the async loaded script if defined,
or :undefined if it's not.
R: It means the jQuery ready event in the main file got executed.
It can be followed by :ok if the
function in the async loaded script
if defined, or :undefined if it's
not.
L: Async loaded script file has been executed.
AR: jQuery ready event in the async loaded script has been
executed.
Test Results
Browsers supporting async:
Google Chrome 11.0.696.68: D:undefined R:undefined L AR
Firefox 4.0.1: D:undefined L R:ok AR
Browsers supporting async but tested without async (expecting same results):
Google Chrome 11.0.696.68: L D:ok AR R:ok
Firefox 4.0.1: L D:ok AR R:ok
Browsers NOT supporting async (expecting same results):
Internet Explorer 9: L D:ok AR R:ok
Opera 11.11: L D:ok AR R:ok
Test Script
test.html
<!DOCTYPE HTML>
<head>
<title>Async Test</title>
<script type="text/javascript">
var result = "";
</script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
<script type="text/javascript" src="test.js" async></script>
<script type="text/javascript">
try{
myFunc();
result += "D:ok ";
} catch(ex) { result += "D:undefined "; }
$(function(){
try{
myFunc();
result += "R:ok ";
} catch(ex) { result += "R:undefined "; }
$('body').text(result);
});
</script>
</head>
<body>
</body>
</html>
test.js
// Fires straight away when this file is loaded.
result += "L ";
$('body').text(result);
// A test function to see if it's defined in certain parts of the main file.
function myFunc(){
return;
}
// A ready function to see if it fires when loaded async.
$(function(){
result += "AR ";
$('body').text(result);
});
This question has bothered me too for quiet some time now.
So I just finished writing "jqinit.js". The purpose of it is managing the dependencies in a way that you can just put them into your html as you did. And you can load jquery with async, too.
It works mainly by checking if jquery has been loaded and delaying execution of you script until it has. As a bonus you can manage dependencies between your scripts, too. And it can be loaded async itself.
Have a look if it fits your needs (feedback welcome): https://github.com/ScheintodX/jqinit.js
I have a script that starts when the page loads and I had been using this code below to start it:
if (window.addEventListener) {
window.addEventListener('load', otherRelatedParts, false);
}
else if (window.attachEvent) {
window.attachEvent('onload', otherRelatedParts );
}
but today I tried with a self invoking function like this:
(function() {
otherRelatedParts();
}())
It seems to work, in all browsers and is less code. Is this the preferred way to add events to the window load?
Your self invoking function will execute earlier than window.onload. It will execute at the moment the browser reads it. In most cases it actually does not make any difference so you can use it this way. Window.load is normally raised when all objects (images, JavaScript files etc) have been downloaded. $(document).ready() triggers earlier than window.onload - when the DOM is ready for manipulation.
I guess the above if clause is written to cover some cross browser issues. You should factor these things out of your code.
As other people have done this before, you might as well use some library as jQuery. You should look for .ready() there.