Web Development

Preloading and the JavaScript Image() object

Lots of high-res images can really spruce up a Web site. But they can also slow it down-- images are files, files use bandwidth, and bandwidth is directly related to wait times. It's time you get yourself an education on how to speed things up with a little trick called image preloading.

Lots of high-res images can really spruce up a Web site. But they can also slow it down—images are files, files use bandwidth, and bandwidth is directly related to wait times. It's time you get yourself an education on how to speed things up with a little trick called image preloading.

Image preloading

The way a browser normally works, images are loaded only after an HTTP request is sent for them, either passively via an <img> tag or actively through a method call. So if you have JavaScript that swaps an image on mouseover, or changes an image automatically after a timeout, you can expect to wait anywhere from a few seconds to a few minutes while the image is retrieved from the server. This is especially noticeable if you have a slow connection to the Internet, or if the images being retrieved are very large...and the delay usually ruins the effect you were hoping for.

Some browsers try to mitigate this problem by storing the images in the local cache so that subsequent calls to the image are satisfied immediately...but there's still a delay the very first time the image is needed. Preloading is a technique where the image is downloaded to the cache before it's needed. That way when the image is really needed it can be retrieved from the cache and displayed immediately.

The Image() object

The simplest way to preload an image is to instantiate a new Image() object in JavaScript and pass it the URL of the image you want preloaded. Say we have an image called heavyimagefile.jpg, which we want to display when the user mouses over an already-displayed image. In order to preload this image for faster response time, we simply create a new Image() object, called heavyImage, and load it simultaneously to the page with the onLoad() event handler:

<html>
<head>
<script language = "JavaScript">
function preloader()
{
heavyImage = new Image();
heavyImage.src = "heavyimagefile.jpg";
}
</script>
</head>
<body onLoad="javascript:preloader()">
<a href="#" onMouseOver="javascript:document.img01.src='heavyimagefile.jpg'">
<img name="img01" src="justanotherfile.jpg"></a>
</body>
</html>

Note that the image tag does not itself handle onMouseOver() and onMouseOut() events, which is why the <img> tag in the example above has been enclosed in an <a> tag, which does include support for those event types.

Loading multiple images with arrays

In practice, you will probably need to preload more than just one image; for example, in a menu bar containing multiple image rollovers, or if you're trying to create a smooth animation effect. This is not difficult; all you need to do is make use of JavaScript's arrays, as in the example below:

<script language="JavaScript">

function preloader()
{

     // counter
     var i = 0;

     // create object
     imageObj = new Image();

     // set image list
     images = new Array();
     images[0]="image1.jpg"
     images[1]="image2.jpg"
     images[2]="image3.jpg"
     images[3]="image4.jpg"

     // start preloading
     for(i=0; i<=3; i++)
     {
          imageObj.src=images[i];
     }

}

</script>

In the above example, you define a variable i and an Image() object cleverly named imageObj. You then define a new array called images[], where each array element stores the source of the image to be preloaded. Finally, you create a for() loop to cycle through the array and assign each one of them to the Image() object, thus preloading it into the cache.

The onLoad() event handler

Like many other objects in JavaScript, the Image() object also comes with some event handlers. The most useful of these is undoubtedly the onLoad() handler, which is invoked when the image has completed loading. This handler can be hooked up with a custom function to perform specific tasks after the image has completed loading. The following example illustrates this by displaying a "please wait" screen while the image loads, and then sending the browser to a new URL once it's finished loading.

<html>
<head>
<script language="JavaScript">

// create an image object
objImage = new Image();
    
// set what happens once the image has loaded objImage.onLoad=imagesLoaded();
    
// preload the image file
objImage.src='images/image1n.gif';

// function invoked on image load
function imagesLoaded()
{   
     document.location.href='index2.html';
}

</script>
</head>

<body>

Please wait, loading images...

</body>
</html>

Of course, you can also create an array of images and loop over it, preloading each one and keeping track of the number of images loaded at each stage. Once all the images are loaded, the event handler can be programmed to take the browser to the next page (or do any other task).

Preloading and Multi-State Menus

Now, how about using all the theory you just learned in an actual application? This next one is a little piece of code I recently had occasion to write - a menu bar consisting of buttons (image links), each of which can be in any one of three states: normal, hover and click. Since the buttons have multiple states, it is necessary to use image preloading to ensure that the menu responds quickly to changes in its state. The code in Listing A illustrates this.

The HTML code in Listing A sets up a menu bar consisting of four buttons, each of which has thee states: normal, hover, and click. The requirements are as follows:

  • On mouse move over a button in normal state, it changes to hover state. On mouse out, it goes back to normal state.
  • On mouse click on a button, it changes to its click state. It remains in this state until another button is clicked.
  • If a button is clicked, no other button may be in click state. Other buttons can only be in their hover or normal states.
  • Only one button may be clicked at a time.
  • Only one button can be in hover state at a time.

The first task is to set up arrays holding the images for each state of the menu. The <img> elements corresponding to these array elements are also created in the HTML document body, and named sequentially. Note that array values are indexed starting from 0, while the corresponding <img> elements are named starting from 1—this gives rise to certain calculation adjustments in the latter half of the script.

The preloadImages() function takes care of loading all the images into the cache, so that response time on mouse movement is minimal. A for() loop is used to iterate over the images created in the first step and preload each one.

The resetAll() function is a convenient way to reset all the images to their normal state. This is necessary because, when an item of the menu is clicked, all other items in the menu must revert to their normal state before the clicked item can change to its click state.

The setNormal(), setHover() and setClick() functions take care of changing the source of a particular image (image number passed as function argument) to its normal, hover, or click state respectively. Since images which are clicked must remain in that state until another image is clicked (see rule #2), they are temporarily immune to mouse movements; thus, the setNormal() and setHover() functions include code to only change a button's state if it is not already in its click state.

The above is just one of the many ways in which preloading can help you speed up the response time of your JavaScript effects. Use the techniques outlined above in your site, and alter them where needed to fit your requirements. Good luck!

0 comments

Editor's Picks