Archive for October, 2011

Preloading resources

Monday, October 3rd, 2011

You might have read that when optimizing your site for speed HTTP requests are something to look at – less requests mean less waiting and usually a faster site. When doing that for CSS you’re faced with a dilemma:

  1. Put all of CSS in one file, which means less requests, but also means that the first time people land on your site, they will wait longer than needed to see the content which could mean a ruined first impression.
  2. Put CSS in per-section files, which means less loading up front but more request as people drill down into different sections of the page.

When using the first option your only focus can be on how to optimize the CSS so that it loads as fast as possible and is as small as possible. As you have less files you can easily have that file minified and gzipped even if you’re not using a deployment solution that will do that for you.

Using the second variant gives you more options – you should still optimize the files, but now you have the option of deciding when to load them to make sure that the landing page does not get hit by the added request.

Even though I started with CSS preloading can be done for any resources needed on the page – fonts, scripts, images.

When to preload?

An very obvious case is a search results page. It usually has a very distinct design that requires certain resources not needed anywhere else. But that’s not enough – you need to know when the user will these resources so you don’t go preloading everything just in case. With search it’s when they focus inside a search box – they start typing the query, while you start preloading the resources in the background.

Other obvious places to preload resources:

  • My account – when users click log-in or focus into the login form
  • Checkout – when users add stuff to their cart

Other less obvious places are landing pages when the choice a user makes turns into many sub-options, especially when products have the same resources used on the content pages.

To the code!

If you’re already using a library it probably provides AJAX methods and event methods. If not, you can search MicroJS to find one and adapt the syntax.

A simple preloader is almost as simple as helloWorld – the only thing you need to make sure is that the type of data type is set to text so that it does not get executed.

window.preload = function (src) {
	$.get(src, null, null, 'text');
} // call with preload('somefile.css');

If you want to allow the loading of multiple files at once you can detect if the passed element is an array.

window.preload = function (data) {
	var a = $.isArray(data) ? data : [data];
	$.each(a, function (i, n) {
		$.get(n, null, null, 'text');
	});
}
// call with preload('somefile.css');
// or preload(['somefile.css', 'otherfile.js']);

If you prefer to call the function with many parameters you can just use arguments in the each function call.

window.preload = function () {
	$.each(arguments, function (i, n) {
		$.get(n, null, null, 'text');
	});
}
// call with preload('somefile.css');
// or preload('somefile.css', 'otherfile.js');

Key element is to load the resources after the window.onload has happened – this means that any resources needed for the page to function properly have been loaded. If you do stuff sooner you might have to wait for other resources like fonts, images, videos. This means you need to know if the onload event happened – if it has, preload immediately, otherwise wait for the event to fire.

(function () {
	var win = window,
		$ = window.jQuery,
		$win = $(win);
	$win.load(function () {
		$win.data('loaded', true);
	});
	win.preload = function (data) {
		var a = $.isArray(data) ? data : [data],
			fn = function (i, n) {
				$.each(a, function () {
					$.get(n, null, null, 'text');
				});
			};
		if ($win.data('loaded')) {
			fn();
		} else {
			$win.load(fn);
		}
	};
}());
// call with preload('somefile.css');
// or preload(['somefile.css', 'otherfile.js']);

As you can see I also did a few other things – wrapped the code into a function to isolate all the variables. I also assigned window.jQuery to a local $ to make it a bit more bulletproof.

Needless to say this script needs to be loaded during the load stage. If you intend to load it afterwards you need to make sure that you properly detect the onload event – if you don’t nothing will get preloaded as it will be waiting for that event to fire.