-
Asynchronous Image Loading with jQuery
Posted on April 9th, 2009 23 commentsI thought it would make for a good change of pace to switch gears from back end development to front end development. So far I’ve focused primarily on php development which makes sense since that is my job here at eROI. There are plenty of opportunities to get my hands dirty doing javascript development, and the folks here at eROI are not shy about their infatuation with jQuery. It’s an awesome framework for frontend development and I expect I’ll be posting more articles about it in the near future.
I recently built a media heavy site that involved loading lots of images on a page that were dynamic. Search results were displayed using thumbnails in a tile format that allowed for quick perusing, something that’s not uncommon at all. One of the annoyances I encounter often with sites that load images is that sometimes the load times for image assets can vary resulting in a broken page layout until the images finish loading.
For my latest project I had a goal to have the entire page layout to render completely and allow the images to flesh out at their leisure without having the page structure move. The effect is pleasing to the eye with a certain ‘coolness’ factor, and by allowing images to load asynchronously using jquery, we can create callbacks to be executed by images that have finished loading. There are lots of cool things we can do with that. To make the whole process look even ‘cooler’, it would be nice to have some form kind of throbber show so that we know we are waiting for something to appear. But wait! That’s not all. One more feature we should have is to be able handle errors, for example if an image asset is missing or corrupt, rather than rely on the browser to show a broken asset indicator, (or worse: nothing at all), we should be able to show a fallback image that indicates a failure occured.
Let’s create a file called image-loader.js. At the top we need to specify a couple of variables to indicate where to pull default assets from:
-
-
gLoadSpinnerUrl = gBaseUrl + ‘/assets/images/ajax-loader.gif’;
-
gFailImage = gBaseUrl + ‘/assets/images/image_load_error.gif’;
-
The gLoadSpinnerUrl is the url of an image asset that will be shown while the real image is loading. This can be any manifestation of an ajax-ish throbber, spinner, progressbar, etc. The gFailImage is the url of the image asset to show if something bad happens and the real image becomes unavailable.
Next we create two functions that make the magic happen. The first function is LoadImage():
-
-
function LoadImage(pSelector, pCallback){
-
var loader = $(pSelector);
-
loader.html(‘<img src="’ + gLoadSpinnerUrl + ‘"/>’);
-
-
LoadThisImage($(img), loader, pCallback);
-
}
-
To this function we pass a jquery selector and an optional callback function. The selector can refer to any type of html element so long as that element has a ’src’ attribute which references the url of the real image we want to load. Typically I use a ‘div’ or an ‘a’ tag which serves as a container element for the img tag that will be dynamically created. Obviously neither of these tags has use for a ’src’ attribute so that leaves it open for us to assign an arbitrary url to it.
The LoadImage function grabs the specified element and immediately inserts an ‘img’ tag referencing our spinner image so that the end user has something to look at while it does its work. Next LoadThisImage() is called:
-
-
function LoadThisImage(loader, pCallback){
-
image_src = loader.attr(’src’);
-
img = new Image();
-
img.hide();
-
-
img.load(function() {
-
cb_js = loader.get(0).getAttribute(‘onload’);
-
onload_cb = function(){
-
eval(cb_js);
-
}
-
-
loader.html(this);
-
loader.removeClass(‘loadable-image’);
-
loader.removeAttr(’src’);
-
loader.removeAttr(‘onload’);
-
$(this).show();
-
if (onload_cb){
-
onload_cb($(this));
-
}
-
if (pCallback){
-
cb = pCallback;
-
cb($(this));
-
}
-
})
-
.error(function() { $(this).attr(’src’, gFailImage).show(); })
-
.attr(’src’, image_src)
-
.show();
-
}
-
This function is passed the container element and the optional callback function. LoadThisImage extracts the ’src’ attribute from the container element and creates a brand new Image object in memory. The ’src’ is then assigned to our new Image and we create some callbacks on the Image by called error() load(), passing each an anonymous function to handle a possible error event and the desired load event.
In the event of an error, we change the ’src’ attribute of the image to show our failure image. If the load is successful, we begin processing any custom callbacks that are present. The first place the function checks in the container element itself. If the container element has an ‘onload’ attribute, it is assumed to have javascript assigned to it which is then evaluated. Next it checks to see if a callback function was passed to the function call manually which is also evaluated. Both callbacks are passed the image object so that they can manipulate the object after it has finished loading. This way we can do things like assign onclick events or alt tags or whatever you can think of.
For convenience we also provide a function called LoadAllImages():
-
-
function LoadAllImages(){
-
$(‘.loadable-image’).each(function(){
-
var loader = $(this);
-
loader.html(‘<img src="’ + gLoadSpinnerUrl + ‘"/>’);
-
LoadThisImage(loader);
-
});
-
}
-
This function takes no arguments. Instead it selects all elements with the class ‘.loadable-image’ and processes them the same way the container is processed in LoadImage. This can be called from a DOM ready function allowing all images on a page to be loaded asynchronously.
Here’s a real world example:
-
-
<script type="text/javascript">
-
$(document).ready(function(){
-
LoadAllImages();
-
});
-
</script>
-
<div class="loadable-image" src="/images/example.jpg" onload="img = $(arguments[0]); img.bind(’click’, function(){ alert(’Image was clicked’); })"></div>
-
In this example we set up our container div with an image src and an inline callback. An img with the src ‘/images/example.jpg’ will be inserted into the div. When the image has downloaded, it will be passed to the javascript in the onload attribute. Since there is no function prototype to indicate parameters, we must access the passed in image dynamically with the arguments array. The callback binds a click handler to the image so that an alert appears when it is clicked. See, it’s simple.
Here’s a screenshot of a site that uses this technique to give you an idea of how it looks:
Here you can see how the page maintains it’s layout while the images are still loading. Spinners are showing for images that have not downloaded yet.
Loading your images this way adds a really cool ‘modern’ feel to the site and provides a workaround for the ugliness that can ensue as pages are rendered before they have finished downloading all of the page assets.
23 responses to “Asynchronous Image Loading with jQuery”
-
Nice Article. I didn’t know it was possible to set a fallback image using javascript.
-
Asynchronous Image Loading with jQuery | Realm of Zod « Netcrema - creme de la social news via digg + delicious + stumpleupon + reddit June 19th, 2009 at 18:42
[...] Asynchronous Image Loading with jQuery | Realm of Zodblog.realmofzod.com [...]
-
If you don’t want for your layout to break just define the width&height attributes on the image (which you should do in any case). You won’t get the fancy loading effect but you will prevent the layout from breaking while loading.
Also users without JavaScript won’t see the images at all. And search crawlers won’t find your images also…
-
IMG.thumbnail-to-load {
height: 100px;
width: 100px;
background: transparent url(spinner.gif) no-repeat center center;
} -
Greetings to the ycombinator folks. I added a link to an example of this in use in your thread but I’ll post it here too: http://community.wacom.com
-
Asynchronous Image Loading with jQuery | Realm of Zod | Tom Altman’s Wedia Conversation June 22nd, 2009 at 21:11
[...] Asynchronous Image Loading with jQuery | Realm of Zod. [...]
-
Is there an active version of this demo available so I can check it out? I am having trouble implementing this to work with a dynamic gallery of Flickr images that I am working with.
-
There is an active version implemented on http://community.wacom.com
-
Is there a direct link to the image loading JS or a chunk of code in particular I can look at? I am checking it with firebug but I am not as experienced with it as others and I can’t find this script in the sea of other things wacom has going on there.
-
If I understand correctly by using this users without Javascript can’t see the images at all, am I right? I’ve been looking for a solid and simple image loader for jQuery that would support several images and not having the image sources in the DOM straight out of the box. This one looks pretty good, but if that’s true it’s a serious usability problem.
-
Good point. I’m sure this is the case for any type of javascript solution you will certainly need to plan for that contingency.
-
hi;
nice script. is there a download for a sample code ?
tks .
jeff -
kapuriya rakesh October 1st, 2009 at 00:44
Nice article.
can u give me sample code for this example. -
Roland October 9th, 2009 at 06:11
Thanks for the article!
Is there any unobstrusive (without having the somewhat quirky ) way to achieve the same effect ?
E.g. having only a
regards, Roland
-
I getting Error img.hide(); not defined. Which
jQuery version your using.Please show the demo if you have link.
-
Try this Image attribute lowsrc.
-
Hey thanks for the cool script, works like a charm!
-
Binyamin December 31st, 2009 at 09:14
Why it does not work on IMG tags:
How to fix it?
-
Binyamin December 31st, 2009 at 09:21
Why it does not work on IMG tags on Chrome and Safari:
[IMG class="loadable-image" src="/images/example.jpg" onload="img = $(arguments[0]); img.bind(’click’, function(){ alert(’Image was clicked’); })” /]Even on DIV tags it works fine just on Firefox.
How to fix it? -
The ‘loadable-image’ class is designed to be put on the element that wraps around the final image as it replaces the elements content.
-
Binyamin January 3rd, 2010 at 03:17
That means it will not display picture hided in DIV SCR, if JavaScript will be turned Off.
Is there some way to ‘create loadable-image’ class for IMG tag? -
Ivan Torres January 28th, 2010 at 23:24
Great script!
Here’s an excellent ajax loading gif generator to customize with color:
-
[...] 1.0 Released Posted on February 3rd, 2010 brandon No comments A while ago I wrote an article on how to dynamically load images using jquery. This has turned out to be one of my most popular posts and I got a lot of feedback on it. As a [...]
Leave a reply
-



