Monday 4 May 2009

jQuery Image Preloading with Callbacks

Googling for image preloaders? Yes that was me and I couldn't find anything which fitted the bill. Needing some form of JavaScript to preload an image and then have a callback function trigger when the image had finished loading (for some pretty transitional effects) I set about writing myself a jQuery plugin (as I use jQuery alot!). The code snippet below could easily be adapted for other libraries and I have tested it in all modern browsers and the onload event seems to trigger nicely in all. Its definately not the best way to add an event handler but as mentioned before it seems the most cross-browser friendly.

So here it comes, what you have been waiting for... Just copy the following into your page or seperate JavaScript file (you can even minify it if its too big for you).

* Update: After the glorious Internet Explorer 8 release it seems my code was causing a sporadic race condition bug. It is due to the code executing so fast that it preloaded the image before it appended it to the DOM causing the code to attempt to remove the element before it existed in the document. Not that this was too much of a problem, it simply left several hidden nodes in the DOM. Not to worry though I have updated the script accordingly to stop this in the future by adding a loaded flag to check if the handler has been triggered.


(function($) {
$.extend(jQuery, {
preloadImage: function(src, callback) {
var i = new Image();
var f = false;
i.onload = function() {
f = true;
if(callback !== undefined) { callback(this); }
$(this).remove();
};
if(!f) {
$(i).attr('src', src).css({
position: 'absolute',
display: 'none',
width: 1,
height: 1
}).appendTo(document.body);
}
}
});
}(jQuery));

The above probably needs a little explanation and rightly so. I use the JavaScript onload event property directly on the image object as jQuery's event handling is a little more advanced and for some reason setting this through addEventListener or attachEvent does not result in the desired effect. Also setting the elements position to absolute and its size to 1x1 might appear to be (stupid) adding extra css for the sake of it, the idea is that on a large image I have had some issues with a flicker and a quick resizing of the page before the browsers rendering kicks in so by setting it to 1x1 and absolute we avoid this eventuality.

So you want to use it in page now eh? Then call it using...


var url = 'http://.../yourimage.jpg';
$.preloadImage(url, function(image) {
alert('The image from ' + $(image).attr('src') + ' has finished preloading...');
});

And there you have it. Image preloading made a doddle. I would like to point out that the above will only work if you are using jQuery but as mentioned before it would be very very (very) easy to modify for another library.

And thats all folks.

1 comment: