javascript
A Simple and Robust jQuery 1.4 CDN Failover in One Line
Google, Yahoo, Microsoft and others host a variety of JavaScript libraries on their Content Delivery Networks (CDN) - the most popular of these libraries being jQuery. But it’s not until the release of jQuery 1.4 that we were able to create a robust failover solution should the CDN not be available.
First off, lets look into why you might want to use a CDN for your JavaScript libraries:
1. Caching - The chances are the person already has the resource cached from another website that linked to it.
2. Reduced Latency - For the vast majority the CDN is very likely to be much faster and closer than your own server.
3. Parallelism - There is a limit to the number of simultaneously connections you can make to the same server. By offloading resource to the CDN you free up a connection.
4. Cleanliness - Serving your static content from another domain can help ensure that you don’t get unnecessary cookies coming back with the request.
All these aspects are likely to add up to better performance for your website - something we should all be striving for.
For more discussion of this issue I highly recommend this article from Billy Hoffman : Should You Use JavaScript Library CDNs? which includes arguments for and against.
The fly in the ointment is that we are introducing another point of failure.
Major CDNs do occasionally experience outages and when that happens this means that potentially all the sites relying on that CDN go down too. So far this has happened fairly infrequently but it is always good practice to keep your points of failure to a minimum or at least provide a failover. A failover being a backup method you use if your primary method fails.
I started looking at a failover solution for loading jQuery1.3.2 from a CDN some months ago. Unfortunately jQuery 1.3.2 doesn’t recognise that the DOM is ready if it is added to a page AFTER the page has loaded. This made making a simple but robust JavaScript failover solution more difficult as the possibility existed for a race condition to occur with jQuery loading after the page is ready. Alternative methods that relied on blocking the page load and retrying an alternative source if the primary returned a 404 (page not found) error code were complicated by the fact that the Opera browser didn’t fire the "load" event in this situation, so when creating a cross-browser solution it was difficult to move on to the backup resource.
In short, writing a robust failover solution wasn’t easy and would consume significant resource. It was doubtful that the benefit would justify the expense.
The good news is that jQuery1.4 now checks for the dom-ready state and doesn’t just rely on the dom-ready event to detect when the DOM is ready, meaning that we can now use a simpler solution with more confidence.
Note that importantly the dom-ready state is now implemented in Firefox 3.6, bringing it in line with Chrome, Safari, Opera and Internet Explorer. This then gives us great browser coverage.
So now in order to provide an acceptably robust failover solution all you need do is include your link to the CDN hosted version of jQuery as usual :
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
and add some JS inline, similar to this:
<script type="text/javascript">
if (typeof jQuery === 'undefined') {
var e = document.createElement('script');
e.src = '/local/jquery-1.4.min.js';
e.type='text/javascript';
document.getElementsByTagName("head")[0].appendChild(e);
}
</script>
You are then free to load your own JavaScript as usual:
<script type="text/javascript" src="my.js"></script>
It should be well noted however that the above approach does not "defer" execution of other script loading (such as jQuery plugins) or script-execution (such as inline JavaScript) until after jQuery has fully loaded. Because the fallbacks rely on appending script tags, further script tags after it in the markup would load/execute immediately and not wait for the local jQuery to load, which could cause dependency errors.
One such solution is:
<script type="text/javascript">
if (typeof jQuery === 'undefined')
document.write('script type="text/javascript" src="/local/jquery-1.4.min.js"><\/script>');
</script>
Not quite as neat perhaps, but crucially if you use a document.write() you will block other JavaScript included lower in the page from loading and executing.
Alternatively you can use Getify’s excellent JavaScript Loading and Blocking library LABjs to create a more solid solution, something like this :
<script type="text/javascript" src="LAB.js">
<script type="text/javascript">
function loadDependencies(){
$LAB.script("jquery-ui.js").script("jquery.myplugin.js").wait(...);
}
$LAB
.script("http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js").wait(function(){
if (typeof window.jQuery === "undefined")
// first load failed, load local fallback, then dependencies
$LAB.script("/local/jquery-1.4.min.js").wait(loadDependencies);
else
// first load was a success, proceed to loading dependencies.
loadDependencies();
});
</script>
Note that since the dom-ready state is only available in Firefox 3.6 + <script> only solutions without something like LABjs are still not guaranteed to work well with versions of Firefox 3.5 and below and even with LABjs only with jQuery 1.4 (and above).
This is because LABjs contains a patch to add the missing "document.readyState" to those older Firefox browsers, so that when jQuery comes in, it sees the property with the correct value and dom-ready works as expected.
If you don’t want to use LABjs you could implement a similar patch like so:
<script type="text/javascript">
(function(d,r,c,addEvent,domLoaded,handler){
if (d[r] == null && d[addEvent]){
d[r] = "loading";
d[addEvent](domLoaded,handler = function(){
d.removeEventListener(domLoaded,handler,false);
d[r] = c;
},false);
}
})(window.document,"readyState","complete","addEventListener","DOMContentLoaded");
</script>
(Adapted from a hack suggested by Andrea Giammarchi.)
So far we have talked about CDN failure but what happens if the CDN is simply taking a long time to respond? The page-load will be delayed for that whole time before proceeding. To avoid this situation some sort of time based solution is required.
Using LABjs, you could construct a (somewhat more elaborate) solution that would also deal with the timeout issue:
<script type="text/javascript" src="LAB.js"></script>
<script type="text/javascript">
function test_jQuery() { jQuery(""); }
function success_jQuery() { alert("jQuery is loaded!");
var successfully_loaded = false;
function loadOrFallback(scripts,idx) {
function testAndFallback() {
clearTimeout(fallback_timeout);
if (successfully_loaded) return; // already loaded successfully, so just bail
try {
scripts[idx].test();
successfully_loaded = true; // won't execute if the previous "test" fails
scripts[idx].success();
} catch(err) {
if (idx < scripts.length-1) loadOrFallback(scripts,idx+1);
}
}
if (idx == null) idx = 0;
$LAB.script(scripts[idx].src).wait(testAndFallback);
var fallback_timeout = setTimeout(testAndFallback,10*1000); // only wait 10 seconds
}
loadOrFallback([
{src:"http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js", test:test_jQuery, success:success_jQuery),
{src:"/local/jquery-1.4.min.js", test:test_jQuery, success:success_jQuery}
]);
</script>
To sum up - creating a truly robust failover solution is not simple. We need to consider browser incompatabilities, document states and events, dependencies, deferred loading and time-outs! Thankfully tools like LABjs exist to help us ease the pain by giving us complete control over the loading of our JavaScript files. Having said that, you may find that in many cases the <script> only solutions may be good enough for your needs.
Either way my hope is that these methods and techniques provide you with the means to implement a robust and efficient failover mechanism in very few bytes.
A big thanks to Kyle Simpson, John Resig, Phil Dokas, Aaoran Saray and Andrea Giammarchi for the inspiration and information for this post.
Related articles / resources:
3.http://aaronsaray.com/blog/2009/11/30/auto-failover-for-cdn-based-javascript/
4.http://snipt.net/pdokas/load-jquery-even-if-the-google-cdn-is-down/
5.http://stackoverflow.com/questions/1447184/microsoft-cdn-for-jquery-or-google-cdn
6.http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html
7.http://zoompf.com/blog/2010/01/should-you-use-javascript-library-cdns/
Internet Explorer Oddities with Custom HTML Tags
I’m currently working on a simple Content Management System that will be a browser based, dare I say Web 2.0 application. I’m fully aware that every man and their dog seems to be creating ’simple’ CMS’s at the moment - but I’m really hoping that ours will be amongst the simplest and easy to use. I won’t go into details here but the idea is that existing content can very easily be highlighted as ‘editable’ without any visible changes to page rendering. Our CMS will also be easy for webmasters to deploy and configure and does not require a database. We’re hoping these will be differentiating factors.
We often develop for the Firefox browser, we have found if our sites and applications work in Firefox they very often work with Opera and Safari browsers with the minimum (if any) of tweaking. Getting things working in Internet Explorer as many web developers will tell you, can be a bit more ‘interesting’.
I’ve been having an ‘interesting’ time recently with our CMS - trying to get custom HTML tags to behave in Internet Explorer. I’ll explain briefly, our CMS works by streaming modified versions of web pages to the browser which contain certain areas that can be edited. As I needed to style and add behaviour to content without altering the display properties of the page I was streaming, I decided to create custom HTML tags that I could wrap around editable content.
Everything was working fine in Firefox, Opera and Safari, but when I tried it out in IE nothing (related to the custom tags) worked. So I created the simplest of examples so I could identify where the problem might lie.
Take the following HTML:
<html>
<head>
<style type="text/css">
custom {
color:#0000FF;
}
custom:hover {
color:#FF0000;
}
</style>
</head>
<custom id="myCustomTagId" onclick="alert(this.id)">
This text should be blue normally and red when hovered over.
When clicked on it should display the tag id.
</custom>
</body>
</html>
Pretty straightforward stuff. The only thing out of the ordinary being the tag. I’ve included the styles inline and they specify that the text inside the custom tag should be blue (#0000FF) while hovering over the text should change the colour to red (#FF0000). Also clicking on the link should result in the custom tag’s Id being displayed.
Firefox, Safari and Opera all perform the expected but Internet Explorer isn’t having any of it.
In an effort to figure out what an earth was going on I googled around and dug up this old chestnut by Dino Esposito on Extending HTML with Custom Tags
Dino readily admits that Internet Explorer doesn’t know how to handle custom tags and that it just ignores them. He then goes on to describe ways around this limitation, which I dutifully read and came up with the following:
<html xmlns:custom>
<style>
@media all {
custom\:default {
color:#0000FF;
}
}
</style>
<body>
<custom:default id="myCustomTagId" onclick="alert(this.id)">
This text should be blue normally and red when hovered over.
When clicked on it should display the tag id.
</custom:default>
</body>
</html>
Which isn’t perfect by any means but did manage to turn the text blue even in IE. Note that the custom tag has to be defined in the format which isn’t ideal but there doesn’t seem to be anyway around it, I guess this is Microsoft’s way of letting us define multiple tags under one namespace. Some progress at least I thought - all I need to do now is add a hover state:
custom\:default:hover {
color:#FF0000;
}
Nope! That doesn’t work. Dino also mentions that you can script custom tag behaviour in something called an HTC file. I’d come across this before in Peterned’s excellent Whatever:Hover script so I modified my HTML:
<html xmlns:custom>
<style>
@media all {
custom\:default {
behavior:url(custom2.htc);
color:#0000FF;
}
}
</style>
<body>
<custom:default id="myCustomTagId" onclick="alert(this.id)">
This text should be blue normally and red when hovered over.
When clicked on it should display the tag id.
</custom:default>
</body>
</html>
and created an HTC file that looks like this:
<PUBLIC:HTC URN="custom2">
<PUBLIC:ATTACH EVENT="onmouseover" HANDLER="turnRed" />
<PUBLIC:ATTACH EVENT="onmouseout" HANDLER="turnBlue" />
<SCRIPT LANGUAGE="jscript">
function turnRed() {
eTD = window.event.srcElement;
eTD.style.color = "#FF0000";
}
function turnBlue() {
eTD = window.event.srcElement;
eTD.style.color = "#0000FF";
}
</SCRIPT>
</PUBLIC:HTC>
And that’s how you get a custom tag to work in Internet Explorer …. kindof.
Note - this will likely not work on any other browser, for it to do so some fancy markup and/or browser sniffing is probably required.
Note 2 - I did try to refine my HTC file to this:
<PUBLIC:HTC URN="custom2">
<PUBLIC:ATTACH EVENT="onmouseover" HANDLER="changeColor('#FF0000')" />
<PUBLIC:ATTACH EVENT="onmouseout" HANDLER="changeColor('#00FF00')" />
<SCRIPT LANGUAGE="jscript">
function changeColor(newColor) {
eTD = window.event.srcElement;
eTD.style.color = newColor;
}
</SCRIPT>
</PUBLIC:HTC>
but that didn’t seem to work either. That would be too easy!
Mark B
Javascript Timers and Opera Mini 2
Opera Mini 2 is out. This is a source of some excitement to me as we have long been interested in developing applications for mobile devices and at long last it looks like we might be able to do this through a browser interface. We’re especially interested to see how well it supports websites written with AJAX technologies.
Opera have made a smart move creating the excellent Opera Mini Simulator. The simulator is not only a cool promotional tool but serves as a useful resource for developers like myself to not only test our websites for compatibility, but more interestingly to test out our mobile AJAX experiments. It was while testing one of these ‘experiments’ I noticed that the Javascript timer function setTimeout didn’t seem to work with the current version of Opera Mini. The timer function is used in AJAX based solutions to achieve visual effects that happen over time (see script.aculo.us and moo.fx) but also for ’suggest’ functionality (see google suggest for an example). So needless to say we were very surprised and not a little disappointed to find that the setTimeout function didn’t seem to work with Opera Mini.
To double check this I created a simple timer based example that can be run from a desktop browser and Opera Mini’s Simulator for comparison.
The Javascript looks like this:
var count = 0;
function refreshPage()
{
count = count + 1;
var counter = document.getElementById("counter");
counter.innerHTML = 'count='+count;
update();
}
function update()
{
setTimeout("refreshPage()",1000)
}
You can see it in action and view the html here.
You should find that it works in your desktop browser but not in the Opera Mini Simulator. Just to check that it wasn’t just me I checked out Google Suggest from within the simulator and although the page rendered beautifully - the suggest part of it didn’t work!

It seems strange to me that Opera have omitted the Javascript timer as the Opera Browser seems an ideal platform to write applications for mobile phones. Looking at their desktop browser strategy of allowing developers to create widgets it seems that they are encouraging developers to create small opera based applications that run outside of the browser and that even work when not connected to the internet!
It’s easy to see the potential for writing ‘write once run anywhere’ applications for mobile phones if they extended the widget strategy to their mobile browser, however it’s going to be very limiting without some sort of javascript timer function! It can’t be true - I must be doing something wrong! I’m off to the Opera forums to find out!
Update - Dec 6th, 2006
Opera Mini 3 has recently been released. Unfortunately it still doesn’t support setTimeout! However Opera for the Nintendo DS does support it! Progress?
Update - Nov 7th, 2007
Opera Mini 4 is out! Still no setTimeout support. Ther’s a telling paragraph in Chris Mills’ article JavaScript support in Opera Mini 4 :
Sites that use Ajax to trigger very regular page changes however, such as Google Suggest and the automatic new mail functionality of GMail mentioned above won’t work. Other examples of things that don’t work are IRC-like chat-clients using server-side events, and clocks.
Mark B
Categories
Archives
- August 2010 (2)
- June 2010 (1)
- March 2010 (1)
- January 2010 (1)
- August 2009 (1)
- July 2009 (1)
- May 2009 (1)
- April 2009 (2)
- March 2009 (1)
- February 2009 (2)
- October 2007 (1)
- May 2006 (1)