Thursday, March 18th, 2010
Category: JavaScript, Performance
A certain someone was talking to me about how they find it interesting that node.js, the JavaScript server framework du jour which loves all things async, starts life with a bunch of synchronous require() calls. Now, this is actually quite fine since the startup of the server is not the issue at hand.
However, if you are running require()-esque loader code in the browser you want to avoid blocking calls else Steve Souders will come over and beat you up.
I have seen a couple of interesting items in this area:
RequireJS
James Burke of Mozilla Messaging has spent a lot of time in the depths of dojo.require(). He has taken another look at the problem and RequireJS a solution that offers:
- some sort of #include/import/require
- ability to load nested dependencies
- ease of use for developer but then backed by an optimization tool that helps deployment
He walks through the problem and why other solutions like LABjs, CommonJS require, and Dojo itself don't cover all of his bases.
The end result is:
JAVASCRIPT:
-
-
// code that runs asynchronously when the library is loaded
-
require(["some/script.js"], function() {
-
//This function is called after some/script.js has loaded.
-
});
-
-
// defining the module and dependencies
-
require.def(
-
// The name of this module
-
"types/Manager",
-
-
// The array of dependencies
-
["types/Employee"],
-
-
// The function to execute when all dependencies have loaded. The arguments
-
// to this function are the array of dependencies mentioned above.
-
function (Employee) {
-
function Manager () {
-
this.reports = [];
-
}
-
-
// This will now work
-
Manager.prototype = new Employee();
-
-
// return the Manager constructor function so it can be used by other modules.
-
return Manager;
-
}
-
);
-
Google Analytics "async add to []" Pattern
When talking to Davis Frank of Pivotal about some Google Analytics code, he pointed me to details about the new GA asynchronous loader that we very excitedly blogged about since GA was such a blocking offender on the Web.
Part of the asynchronous API is that you, the developer create an array, and use the push() method to put commands on a queue. This means that you can start pushing commands immediately.
Then, when the GA code loads asynchronously, it takes over that array and wraps those standard methods. Now it can take the commands and fire them back to GA and push() can do more. Freaking brilliant.
Wednesday, March 10th, 2010
Category: HTML, Performance
Good old Kangax has been playing with HTML minification and has shared his new tool in an early stage.

What does it do?
Kangax has forked John Resig's HTML parser which parses the HTML and sends that into the Minifier. This has rules that do things like whitespace optimization, comment removal, and collapsing boolean attributes (e.g. disabled="true" -> disabled).
He also has a linter going:
While working on minifier, I realized that oftentimes the most wasteful part of the markup is not white space, comments or boolean attributes, but inline styles, scripts, presentational or deprecated elements and attributes. None of these can be simply stripped, as that could affect state of the document and is just too obtrusive. What can be done, however, is reporting of these occurences to the user. HTMLLint is even a smaller script, whose job is exactly that—to log any deprecated or presentational elements/attributes encountered during parsing. Additionally, it detects event attributes (e.g. onclick, onmouseover, etc.). The rationale for this is that moving contents of event attributes to external script allows to take advantage of resource caching.
Friday, March 5th, 2010
Category: Browsers, Performance
Bass Schouten is a cool name, and the Mozillan has presented Direct2D hardware acceleration.
You have to grab Firefox nightly, do the about:config / gfx.font_rendering.directwrite.enabled game, but then you get to see it in action.
IE9 showed off how they will support hardware rendering, and I am sure we will see more at MIX, but it is very cool to see this across the board.
CSS Transforms/Transitions/Animations are going to feel like butter in 2010!
Monday, March 1st, 2010
Category: Performance
Would we all like Steve to sit down with us on our project and do a performance case study? Well, we may not get that, but we are getting to at least sit in on others.
Steve has kicked off his long awaited series that runs performance case studies on third party content. I have been talking to Steve about this for a couple of years, so it is great to see it. It is a sensitive topic as you never want to show up a team when you are just trying to help and educate.
First on the block? The Digg widget.

Steve goes into detail and finds a lot of short comings. You could probably guess some of the bad actors. Mr. document.write() appears for example. We get the problems, and proposed solutions to the issue. Steve also tries to note what a user of third party content can do regardless of if the third party guys fix their issues (put in iframe!).
Here are the most important performance issues along with recommended solutions.
- 9 HTTP requests, 52 kB transferred over the wire, and 107 kB of JavaScript (uncompressed) is a lot of content for a single widget.
Recommendations:
- Concatenate these three scripts: JS_Libraries, widgetjsvars, and omnidiggthis. (eliminates 2 HTTP requests)
- Run Page Speed’s “Defer loading JavaScript” feature and see how much of the JavaScript is not used. If it’s sizable, delete it. (This feature is currently broken in the latest version of Page Speed, but a fix is imminent.) (eliminates ?? kB)
- Optimize the images – widget-logo.png and get-widget.png can both be reduced by ~3 kB. (eliminates ~6 kB)
- Sprite widget-logo.png and shade-com.png. (eliminates 1 HTTP request)
- The widget’s scripts block the main page’s content from downloading. Looking at the waterfall chart, the main page includes the image “digg-waterfall.png” (row 10). Notice how this image doesn’t start downloading until after all the scripts for the Digg widget are received.
Recommendations:
- Instead of loading the scripts using document.write, load them without blocking other downloads. The scripts are already suffering from race condition behavior, as evidenced by this comment from widgetjsvars:
| 1: |
if (!digg || !digg.$) setTimeout(function() { diggwb(obj); }, 200); //hack for IE not loading scripts that are included via document.write until it decides too |
So it probably isn’t too much work to avoid race conditions when making all the scripts load asynchronously.
- The widget’s stylesheet blocks the main page from rendering in IE.
Recommendations:
- Instead of loading the stylesheet using document.write, load it via JavaScript as described in 5d dynamic stylesheets.
- Four of the resources aren’t cached long enough.
Recommendations:
- Two scripts aren’t cacheable because they have an expiration date in the past. widgetjs is part of the snippet, so it can’t have a long expiration date, but something like an hour or a day would be better than a date in the past. widgetjsvars could have a far future expiration date since its URL is specified in widgetjs.
- The three images are only cacheable for a day. They should have a far future expires header since the image filename can be change if it’s modified.
- There are approximately 30 inefficient CSS selectors. Because this stylesheet is part of the main page, the selectors will cause the overall page to render more slowly when these selectors are applied to the elements in the main page.
Recommendations:
- Four of the resources have ETags which reduces their cacheability.
Recommendations:
- Configure the ETags for widget.css, widget-logo.png, get-widget.png, and shade-com.png.
This is just the first example. What else would you like to see Steve tackle?
Saturday, February 27th, 2010
Category: JavaScript, Mozilla, Performance
David Anderson: "TraceMonkey has rocket boosters, so it runs really fast when the boosters are on, but the boosters can’t always be turned on."
Opera's new JIT compiler Carakan is doing well as we just posted. What is Mozilla doing with TraceMonkey? A lot.
Mozilla JägerMonkey adds method based JIT (of V8 and Nitro fame) to keep the boosters on.
We learn more from David Mandelin and David Anderson.
Monday, February 22nd, 2010
Category: Browsers, Performance
Steve Souders has put together a browser performance wishlist that answers the question "What are the most important changes browsers could make to improve performance?"
He also notes a couple of new ideas that he is very much behind:
SPDY
SPDY is a proposal from Google for making three major improvements to HTTP: compressed headers, multiplexed requests, and prioritized responses. Initial studies showed 25 top sites were loaded 55% faster. Server and client implementations are available, and some other organizations and individuals have completed server and client implementations. The protocol draft has been published for review.
FRAG
The idea behind this “document fragment” tag is that it be used to wrap 3rd party content – ads, widgets, and analytics. 3rd party content can have a severe impact on the containing page’s performance due to additional HTTP requests, scripts that block rendering and downloads, and added DOM nodes. Many of these factors can be mitigated by putting the 3rd party content inside an iframe embedded in the top level HTML document. But iframes have constraints and drawbacks – they typically introduce another HTTP request for the iframe’s HTML document, not all 3rd party code snippets will work inside an iframe without changes (e.g., references to “document” in JavaScript might need to reference the parent document), and some snippets (expando ads, suggest) can’t float over the main page’s elements. Another path to mitigate these issues is to load the JavaScript asynchronously, but many of these widgets use document.write and so must be evaluated synchronously.
A compromise is to place 3rd party content in the top level HTML document wrapped in a FRAG block. This approach degrades nicely – older browsers would ignore the FRAG tag and handle these snippets the same way they do today. Newer browsers would parse the HTML in a separate document fragment. The FRAG content would not block the rendering of the top level document. Snippets containing document.write would work without blocking the top level document. This idea just started getting discussed in January 2010. Much more use case analysis and discussion is needed, culminating in a proposed specification. (Credit to Alex Russell for the idea and name.)
Sunday, February 14th, 2010
Category: Performance
Steve Souders has done a weekly set of posts on browser quirks that have caught his eye. Here's the roundup:
Missing schema double download
Internet Explorer 7 & 8 will download stylesheets twice if the http(s) protocol is missing. Interestingly, I rarely see anyone use "//stevesouders.com/images/book-84x110.jpg" but here is a case to watch out for it.
document.write scripts block in Firefox
Scripts loaded using document.write block other downloads in Firefox. Unfortunately, document.write was invented. That problem was made a bzillion times worse when ads decided to use document.write to insert scripts into the content publisher’s page. It’s one line of code:
JAVASCRIPT:
-
-
document.write('<script src="http://www.adnetwork.com/main.js"><\/script>');
-
Fortunately, most of today’s newer browsers load scripts in parallel including scripts added via document.write. But a few weeks ago I noticed that Firefox 3.6 had some weird blocking behavior in a page with ads, and tracked it down to a script added using document.write.
The document.write scripts test page demonstrates the problem. It has four scripts. The first and second are inserted using document.write. The third and fourth are loaded the normal way (via HTML using SCRIPT SRC). All four scripts are configured to take 4 seconds to download. In IE8, Chrome 4, Safari 4, and Opera 10.10, the total page load time is ~4 seconds. All the scripts, even the ones inserted using document.write, are loaded in parallel. In Firefox, the total page load time is 12 seconds (tested on 2.0, 3.0, and 3.6). The first document.write script loads from 1-4 seconds, the second document.write scripts loads from 5-8 seconds, and the final two normal scripts are loaded in parallel from 9-12 seconds.
media=print stylesheets
Stylesheets set with media=”print” still block rendering in Internet Explorer.
I’m surprised browsers haven’t gotten to the point where they skip downloading stylesheets for a different media type than the current one. I’ve asked some web devs but no one can think of a good reason for doing this. In the meantime, even if you have stylesheets with media="print" you might want to follow the advice of Page Speed and YSlow and put them in the document HEAD. Or you could try loading them dynamically.
dynamic stylesheets
You can avoid blocking rendering in IE if you load stylesheets using DHTML and setTimeout.
A few weeks ago I had a meeting with a company that makes a popular widget. One technique they used to reduce their widget’s impact on the main page was to load a stylesheet dynamically, something like this:
JAVASCRIPT:
-
-
var link = document.createElement('link');
-
link.rel = 'stylesheet';
-
link.type = 'text/css';
-
link.href = '/main.css';
-
document.getElementsByTagName('head')[0].appendChild(link);
-
Most of my attention for the past year has been on loading scripts dynamically to avoid blocking downloads. I haven’t focused on loading stylesheets dynamically. When it comes to stylesheets, blocking downloads isn’t an issue – stylesheets don’t block downloads (except in Firefox 2.0). The thing to worry about when downloading stylesheets is that IE blocks rendering until all stylesheets are downloaded1, and other browsers might experience a Flash Of Unstyled Content (FOUC).
Speculative background images
Chrome and Safari start downloading background images before all styles are available. If a background image style gets overwritten this may cause wasteful downloads.
When my office-mate, Steve Lamm, pointed out this behavior to me, my first reaction was “that’s wasteful!” I love prefetching, but I’m not a big fan of most prefetching implementations because they’re too aggressive – they err too far on the side of downloading resources that never get used. After my initial reaction, I thought about this some more. How frequently would this speculative background image downloading be wasteful? I went on a search and couldn’t find any popular web site that overwrote the background-image style. Not one. I’m not saying pages like this don’t exist, I’m just saying it’s very atypical.
On the other hand, this speculative downloading of background images can really help performance and the user’s perception of page speed.
Friday, February 12th, 2010
Category: Performance
When testing our applications for performance, how do we go about timing various parts and pieces? Normally we are forced to manually get Date.now / new Date().getTime() times and futz around. It isn't possible to get at timing info for important lifecycle events (e.g. can only start timing once JS is loaded.
This is where the Web Timing API comes into play, which seems to be in the early process of implementation in Chromium and Firefox.
With the API there is access to window.timing and element.timing.
An example of using the global window.timing:
JAVASCRIPT:
-
-
var navigation = timing[0];
-
if (navigation.document.load> 0) {
-
var page_load_time = navigation.document.load - navigation.navigationStart;
-
if (navigation.navigationType == navigation.NAVIGATION_LINK) {
-
console.log (page_load_time);
-
}
-
}
-
Within a timing result you have access to a slew of information:
JAVASCRIPT:
-
-
interface DOMTiming {
-
readonly attribute unsigned longlong fetchStart;
-
readonly attribute unsigned longlong domainLookupStart;
-
readonly attribute unsigned longlong domainLookupEnd;
-
readonly attribute unsigned longlong connectStart;
-
readonly attribute unsigned longlong connectEnd;
-
readonly attribute unsigned longlong requestStart;
-
readonly attribute unsigned longlong requestEnd;
-
readonly attribute unsigned longlong responseStart;
-
readonly attribute unsigned longlong responseEnd;
-
readonly attribute unsigned longlong load;
-
readonly attribute unsigned longlong parseStart;
-
readonly attribute unsigned longlong parseEnd;
-
};
-
I am sure that Steve is happy :)
Thursday, January 28th, 2010
Category: Browsers, Canvas, Performance

The Freeciv.net crew has benchmarked a path in their canvas game. It is one data point, and tests more than just Canvas itself because a lot of code is running in the game. Thus, it ends up testing the union of a particular JavaScript path and the rendering of the canvas.
Here are the results:

With Bespin we had slightly different results, and the bulk of the bottleneck was in the blitting of the canvas. Optimizations were made to canvas over the initial phase of Bespin so the various browsers would leap frog each other. Good times :)
Friday, January 15th, 2010
Category: CSS, JavaScript, PHP, Performance
I am right now working on a high-traffic project that will run in a sandbox that doesn't allow me to pull third party JavaScript or use canvas/Flash. Yet I need to generate bar charts from a set of data.

The solution to me was to create the charts from HTML using CSS. There have been some solutions for this problem already but I wanted something very simple and easy to maintain. Hence all the markup I am using is this:
XML:
-
<ul>
-
<li><span>400</span></li>
-
<li><span>20</span></li>
-
<li><span>30</span></li>
-
<li><span>233</span></li>
-
</ul>
Instead of hard-coding any of the trickery necessary I wrote a PHP script to generate the HTML, the styles and do all the math. So all that is needed to render one of the charts is the following code:
PHP:
-
<?php
-
$values = '400,20,30,233,312,78,20,67';
-
$height = 100;
-
$width = 600;
-
$bargap = 0;
-
include('csscharts.php');
-
?>
Of course, this can also be turned into a web service - you can get the chart with the following URL:
http://icant.co.uk/csscharts/csscharts.php?values=400,20,30,233,312,78,20,67&height=100&width=600&bargap=0
And if you specify JSON as the format you get it with a callback to a function called csscharts:
http://icant.co.uk/csscharts/csscharts.php?values=400,20,30,233,312,78,20,67&format=json
JAVASCRIPT:
-
csscharts(
-
{
-
chart:"<ul class=\"barchart\" [… the rest of the html …]</ul>"
-
}
-
)
That way you can use it in JavaScript:
JAVASCRIPT:
-
<script>
-
function csscharts(o){
-
var container = document.getElementById('container');
-
c.innerHTML = o.chart + c.innerHTML;
-
}
-
</script>
-
<script src="http://icant.co.uk/csscharts/csscharts.php?values=400,20,30,233,312,78,20,67&format=json"></script>
You can see some demos here, get detailed info about the CSS trickery used and of course download the code on GitHub.
Wednesday, December 30th, 2009
Category: Performance
The WebKit Inspector tool has a new tab, the Audits panel which aims to be like Google PageSpeed and YSlow! built right in.
A little crude, but good to see:


Saturday, December 12th, 2009
Category: Performance
Rob Flaherty has done a little experimenting with data URIs and performance. The study only looked at Firefox 3.5 with empty cache, but the results were interesting for the questions they raise as much as the answers the provide.
He used a CSS file with 31 images and converted them all to data URIs using Nick Zakas's CSSEmbed. For an extra variant, he used DURIS to extract the data URIs to a separate CSS file so that the basic CSS in <head> becomes much smaller and therefore loads much faster.
All three scenarios yielded similar performance - with HTTPWatch, the times were 1.35s, 1.13s, and 1.13s. So the two data URI scenarios were only marginally better. But more interestingly, a commenter from South Africa chimed in with wildly different results (using Firebug): 4.04s, 1.44s, 1.92s. The implication is clear: latency can be a big factor in some cases, and round-tripping to fetch 31 images is going to bring that out.
Another interesting factor is perceived speed. This is, after all, arguably the most important thing when it comes to performance. Although the two data URI scenarios completed in the same speed, the second setup felt faster because it got the images out of the way and allowed the main stylesheet to load fast. The data URI images were then loaded in a stylesheet at the bottom of the page, after a script had been loaded.
The study also raises questions about data URI loading. A commenter posted a waterfall showing the data URI images take significantly longer to load than regular downloaded images. This is the kind of thing that needs more research and why the study is interesting because of the questions it raises.
Rob also posted a study recently on background-image performance in various browsers.
Thursday, December 3rd, 2009
Category: Editorial, Performance

"View Source is your friend", we've learned countless times as web developers. It's something special about web development that we can seamlessly lift the covers on anything we see and find out how the sausage is made. And it gets even better with great tools to interrogate the system in real-time. This capability has helped us evolve practices and patterns, and contributed to the production of many a fine browser extension and Greasemonkey script.
Our friend might sadly be going the way of the blink tag. View Source has always worked because the standard development model is to put up some static Javascript files on a server somewhere and serve them out. That model is changing though; performance is a very hot topic right now, and View Source is playing victim to that trend.
Google's Let's Make the Web Faster initiative is a case in point. Here is a multi-pronged attack on the performance issue, involving new protocols (SPDY), tools (PageSpeed), browser improvements (Chrome), on-demand loading (Closure), and - most pertinent - compression techniques (Closure again). And we ain't seen nothing yet; there's every reason to believe Google will soon be putting its money where its mouth is, by rewarding faster sites with higher rankings. (I guess I was alone in assuming they always did that.) While performance should always be a consideration for site owners, a dangling SEO carrot would no doubt convert the best of intentions into the most concrete of actions.
Site owners can't (much) control factors such as browser choice and browser efficiency, but they can get their own performance-fu in order, and code compression is low-hanging fruit. Looking at the top 20-ranked sites, filtering only English-language sites, I found the very top guys (Google, Facebook, Yahoo, YouTube, Windows Live) predominately using Javascript compression, with the others not using it much, if at all. I expect most of them to be using it in the next 12-24 months.
In addition to compression, there is also obfuscation. With Javascript being used for more complex tasks and replacing desktop functionality, more companies will be wondering about all that intellectual property sitting in plain view. (And let's not mention the security-by-obscurity fans, who will also go this route, however flawed their thinking.)
Is it all bad? No. There's a much healthier respect for plain old semantic HTML these days, which means HTML documents should be View Sourcier now than ever before. (CSS, not so much, with compression also likely to grow.) If I had to choose between one or the other, I'd take clear HTML over clear Javascript. Also, we will probably find the majority of sites in the long tail won't feel the need to do anything about their code (but the ones who do make efforts are probably the ones with the most interesting things to look at). Also, the aforementioned tools, which do things like XHR sniffing, will help us to understand from a "black box" perspective even if we can't peer into the code. Hopefully, there will also be more attention paid towards Javascript beautifiers as well, to make sense of compressed code.
I can't speculate on the waning of View Source without mentioning the tremendous counter-balancing act played out by Open Source. From the get-go, open source has played a vital role in Ajax, with individuals and companies releasing code for all sorts of reasons. Most of this is library and framework code, rather than production-ready applications, so we might lose something there, but we still have much to gain from the ever-growing corpus of code that's out there, free to be studied and incorporated into our own applications.
Wednesday, December 2nd, 2009
Category: Performance
I heard a huge cheer from the Internet today and found that Google Analytics has launched async mode which finally unclogs our browsers from blocking.
Steve Souders must have had the loudest cheer, and wrote up his view:
The pain of loading JavaScript files is that they block the page from rendering and block other resources from downloading. There are workarounds to these problems. Chapter 4 of Even Faster Web Sites describes six techniques for Loading Scripts Without Blocking. One of those, the Script DOM Element approach, is the technique used in the new Google Analytics async pattern. Google Analytics’ ga.js file is a perfect example of a script that should be loaded asynchronously - it doesn’t add any content to the page, so we want to load it without blocking the images and stylesheets that give users what they really came to see.
Improved Uptime
What happens if a script takes a long time to load, or fails to load? Because scripts block rendering, users are left staring at an empty page. Google Analytics has an amazing infrastructure behind it, but any resource, especially from third parties, should be added cautiously. It’s great that the GA team is evangelizing a pattern that allows the web site to render while ga.js is being downloaded.
To get going, simply change your ga script code to follow the pattern:
JAVASCRIPT:
-
-
var _gaq = _gaq || [];
-
_gaq.push(['_setAccount', 'UA-XXXXX-X']);
-
_gaq.push(['_trackPageview']);
-
-
(function() {
-
var ga = document.createElement('script');
-
ga.src = ('https:' == document.location.protocol ?
-
'https://ssl' : 'http://www') +
-
'.google-analytics.com/ga.js';
-
ga.setAttribute('async', 'true');
-
document.documentElement.firstChild.appendChild(ga);
-
})();
-
It’s extremely cool to see this pattern being evangelized for such a major piece of the Internet. A few items of note:
- Obviously, you have to replace “UA-XXXXX-X” with your ID.
- Since ga.js is being loaded asynchronously, there has to be a way for web site owners to couple their desired GA functions with the code when it finishes loading. This is done by pushing commands onto the Google Analytics queue object, _gaq.
- Once all your callback commands are queued up, the ga.js script gets loaded. This is wrapped inside an anonymous function to avoid any namespace conflicts.
- Inside the anonymous function is where we see the Script DOM Element approach being used - with two nice improvements. A ’script’ element is created and its SRC is set to the appropriate ga.js URL. Looking ahead to support of asynchronous scripts in HTML5, the ‘async’ attribute is set to ‘true’. Very nice! The main benefit of this is it tells the browser that subsequent scripts can be executed immediately - they don’t have to wait for ga.js. The last line adds the script element to the DOM. This is what triggers the actual download of ga.js. In most of my code I do document.getElementsByTagName(”head”)[0].appendChild, but that fails if the document doesn’t have a head element. This is a more robust implementation.
Monday, November 30th, 2009
Category: Performance
Stoyan Stefanov is all about the performance of web products. One small tool that gives you a bit of insight as to where you can optimize is a new bookmarklet he released today called statsy.
If you run statsy on a web site you get the following insights:
JS attributes (e.g. onclick) - this is the sum of all onclick, onmouseover and so on including the attribute names. So for example <a onclick="#"> is 11 characters (bytes) of JavaScript attributes code
CSS style attributes - the sum of all style="..."
Inline JS - the sum of all the contents of all script tags (excluding the tag itself)
Inline CSS - sum of all <style> tag contents
All innerHTML - this is document.documentElement.innerHTML.length, it should be close to the ungzipped size of a page, provided the page is not doing a lot of DOM manipulation
# DOM elements - the total number of elements on the page is counted simply using document.getElementsByTagName('*').length
On Ajaxian, this is the result:

You can install statsy by dragging the following link to your link bar: Statsy and the source is also available.
Nothing earth-shattering but a good tool to use together with YSLow or PageSpeed.
Category: Performance
We have posted about LABjs before, the library that aims to be able to effectively load any script resource(s), from any location, into any page, at any time. It loads them all as parallel as the browser will allow, but maintains execution order when you express the need to do so in the usage of the API, for keeping dependencies safe.
At JSConf.EU in Berlin, I saw Steve Souders and Kyle Simpson riffing on how to make LABjs follow the research that Steve (in his newest book) and Kyle have done.
There were issues in the past, but we now have a new release of LABjs that does the right thing, as long as you wait():
JAVASCRIPT:
-
-
$LAB
-
.script("framework.js").wait()
-
.script("plugin.framework.js")
-
.script("myplugin.framework.js").wait()
-
.script("init.js");
-
Give it a whirl, and read the full post for details on performance and issues with flashing in before behaviour has been added... which leads us to the cavaet on jQuery and DOM ready.
Also, if you think that you should be just concat'ing all of the files into one, see why Kyle thinks you should potentially think again.
As I wrote this another library called NBL came in from "Berklee". He told us:
The other day I tasked myself with rewriting our company's website in HTML5 and I really wanted to improve performance all across the board. So after rewriting the HTML and CSS, I looked to JavaScript lazy loading to increase performance. After searching for a small library to do this and not finding anything not requiring jQuery, or unable to handle network timeouts, I decide to write my own non-blocking lazy loader.
It's called NBL and comes down to 1187 bytes minified. It runs stand-alone and has several options that I could not find in any other library:
1. It can load plugins for your JavaScript framework *after* the framework has been loaded (jQuery is considered the default, but you can override it with any other framework and keep this behaviour).
2. You can provide a callback function that fires when all scripts are loaded, or if you use jQuery, the callback will be fired by jQuery's document.ready() function (unless the page finishes before jQuery initialises, in which case it fires when all scripts are loaded).
3. In case of network latency (or faulty urls), NBL will fire the callback function after a timeout (by default 1200ms).
4. It does not need to be called, it can be configured completely from the script tag itself, like this:
HTML:
-
-
<script type="text/javascript" src="nbl.js" opt="{ urchin: 'http://www.google-analytics.com/urchin.js',
-
plugins: [ 'jquery.lightbox.min.js', 'jquery.carousel.min.js' ], ready: my_ready_function }" />
-
Next Page »