Preloading Images

by kirupa   |   22 October 2013

  Have questions? Discuss this HTML tutorial with others on the forums.

There will be a few times in your life you will find yourself in a situation that requires you to preload images. I am 27 years old, and I found myself in that situation one evening. That was quite embarrassing, and I simply wasn't prepared.

In this tutorial, you will learn how not to find yourself in that situation. You will learn how to preload your images.

When You Need to Preload Images

The times you will need to preload images will almost always involve JavaScript and some degree of interactivity. One common example is when you are creating an image rollover:

rollover example

[ click here to see a live example! ]

Let's broaden this example a bit. Let's you have an image defined in your HTML. As the page is loading, your browser sees this image, downloads it for you, and caches it for use later. Everything is good.

When you have some JavaScript that dynamically specifies an image for display, such as during a rollover, your browser has no prior knowledge about that image. So, instead of seeing the new image as part of your rollover immediately, you will be waiting for the image to download first. This delay is unfortunate and makes your site or application look bad. It is embarrassing!

What you need to do is load any images that will be used dynamically into your browser's cache. This is known as preloading. Once those images are preloaded, using them via JavaScript will result in them appearing instantaneously without your browser having to go out and download the image and making the user wait.

The Code for Preloading an Image

The code for preloading images looks as follows:

this.addEventListener("DOMContentLoaded", preloadImages, true);

function preloadImages(e) {
	var imageArray = new Array("path/image.png", "path/image2.png", "path/image3.png");

	for (var i = 0; i < imageArray.length; i++) {
		var tempImage = new Image();
		
		tempImage.addEventListener("load", trackProgress, true);
		tempImage.src = imageArray[i];
	}
}

All you need to do is modify the values in your imageArray array to be the absolute or relative path to the images you want to load:

var imageArray = new Array("images/ac3.jpg", "images/acr.jpg");

This is just an array, so you can add or remove values as you see fit.

Example

You may have seen this earlier, but if you are having any difficulties getting the code to work, take a look at my Assassin's Creed rollover example.

You can verify that the preloading works by using a tool like Firebug and examining the network data. When your page loads, you should see an entry for every image you specified in your imageArray.

For example, you will see the acr.jpg and ac3.jpg images when I load our example:

example of network data

[ here is the network data showing that my preloading works ]

If you do not see your images getting downloaded early on, your code isn't working as expected. Your browser doesn't have a cached version of the image to display almost instaneously when you need it.

Looking at the Code

We are almost done. The last thing we will do is just take a few steps back and learn why the code works the way it does to preload images for you.

Our full code, again, looks as follows:

this.addEventListener("DOMContentLoaded", preloadImages, true);

function preloadImages(e) {
	var imageArray = new Array("path/image.png", "path/image2.png", "path/image3.png");

	for (var i = 0; i < imageArray.length; i++) {
		var tempImage = new Image();
		
		tempImage.addEventListener("load", trackProgress, true);
		tempImage.src = imageArray[i];
	}
}

Let's go through each line in detail starting at the top:

this.addEventListener("DOMContentLoaded", preloadImages, true);

In this line we are listening for the DOMContentLoaded event and calling the preloadImages function when that event is fired. I discuss this event and what it does in great detail in the Running Scripts at the Right Time tutorial, but just know for know that this event is fired once all of the DOM elements in your page are created.


Once our DOM has loaded, we call the preloadImages function. In the first line of the preloadImages function, we declare our imageArray that contains a list of all the images we want to preload:

var imageArray = new Array("path/image.png", "path/image2.png", "path/image3.png);

This is just your typical array, so you can do all kinds of array things to it. You can learn more about them in my Arrays in JavaScript tutorial.


This now leads us to the next and final chunk of code:

for (var i = 0; i < imageArray.length; i++) {
	var tempImage = new Image();
	tempImage.src = imageArray[i];
}

Here we have a for loop that iterates through all of the items in our imageArray. For each item, we first create a new Image object called tempImage:

var tempImage = new Image();

This object is basically an in-memory represenation of an image element you may normally see in HTML. This allows us to do something like the following:

tempImage.src = imageArray[i];

We set src property on tempImage to the URL of an image stored by the imageArray variable. The moment you do this, your browser begins to download the image you are referencing.

At the end of this loop running to completion, your browser will have a queue of images to download that will then be cached for instantaneous access later!

Going Further : Waiting for Images to Load

For many situations, preloading your images is one thing. Making sure users don't interact with any content while the images are loaded is another. Fortunately, the code change needed to wait for all of your images to load before you do something with them is reasonably straightforward.

Below, I've modified the code you had earlier and highlighted the changes:

this.addEventListener("DOMContentLoaded", preloadImages, true);

var loadedImages = 0;
var imageArray = new Array("path/image.png", "path/image2.png", "path/image3.png)";

function preloadImages(e) {
	for (var i = 0; i < imageArray.length; i++) {
		var tempImage = new Image();
		
		tempImage.addEventListener("load", trackProgress, true);
		tempImage.src = imageArray[i];
	}
}

function trackProgress() {
	loadedImages++;
	
	if (loadedImages == imageArray.length) {
		imagesLoaded();
	}
}

function imagesLoaded() {
	// do something
}

The main change is that I listen to the load event on our tempImage object. The load event only fires when your image has fully downloaded, so I use the trackProgress event handler to keep count of how many images have loaded and how many images we have in total:

function trackProgress() {
	loadedImages++;
	
	if (loadedImages == imageArray.length) {
		imagesLoaded();
	}
}

Once all of the images have loaded, we call the imagesLoaded function where you can put all of the code that you want to execute only after all of your images have loaded.

The full preloading example I've been pitching a few times uses this code to ensure the rollover effect doesn't really do anything until both our images have downloaded. Do check it out if you are having difficulty getting the code to work as intended.

Conclusion

Well, there you have it - a tutorial all about preloading images. As you saw, this implementation makes heavy use of JavaScript. There are ways you can use CSS to try do something simlar as demonstrated by the awesome Jeff Starr.

Use whichever approach you feel makes sense for you, but I prefer the JavaScript solution. A common concern about going with a JavaScript-only solution is knowing how to handle situations where JavaScript is disabled. I don't worry about those situations as much any more.  As web sites and applications get more and more interactive, I think the number of people who actually disable JavaScript will be fairly small. As always with a JavaScript-only solution, make sure you keep accessibility in mind, though.

Getting Help

If you have questions, need some assistance on this topic, or just want to chat - post in the comments below or drop by our friendly forums (where you have a lot more formatting options) and post your question. There are a lot of knowledgeable and witty people who would be happy to help you out

Share

Did you enjoy reading this and found it useful? If so, please share it with your friends:

If you didn't like it, I always like to hear how I can do better next time. Please feel free to contact me directly via e-mail, facebook, or twitter.

Kirupa Chinnathambi
I like to talk a lot - A WHOLE LOT. When I'm not talking, I've been known to write the occasional English word. You can learn more about me by going here.

Add Your Comment (or post on the Forums)

blog comments powered by Disqus

Awesome and high-performance web hosting!
BACK TO TOP
new books - yay!!!