Precaching images in jQuery: A (slightly) better way

Mar 18 2009

Matt Farina has suggested one method of precaching images using jQuery. But in some applications, this will not give the necessary cache lifetime (at least not in FF3) to warrant the extra network requests. Here, I suggest a slight modification that will make the cache last longer. <!--break--> The suggested solution looks something like this (rewritten from his version for brevity):

// Array of images:
var imageArray = ['image1.jpeg', 'image2.png', 'image3.gif'];

// Loop through and declare an element that will not actually be used.
$.each(imageArray, function (i, val) {
  $('<img/>').attr('src', val);
});

The basic idea of the above is this: By creating an img element and adding a src attribute, we force the browser to load the image.

But here's the problem: The image gets garbage collected very quickly after page load. So if the images aren't used right away, they go away. When they are referenced later, the browser has to re-retrieve them.

Caveat: The performance analysis of these two methods was by no means scientific, and it is possible that I just got very lucky in regards to the garbage collector's timing. If your tests reveal different results, please comment.

Extending the cached life of the image

This garbage collecting behavior seems pretty consistent in FF3. Images loaded but not added to the DOM seem to go away very quickly. But it appears that we can do another little trick to extend the cache lifetime. What we need to do is insert the image into the doc inside of a hidden element:

// Array of images:
var imageArray = ['image1.jpeg', 'image2.png', 'image3.gif'];

// Add hidden element
var hidden = $('body').append('<div id="img-cache" style="display:none/>').children('#img-cache');

// Add images to hidden element.
$.each(imageArray, function (i, val) {
  $('<img/>').attr('src', val).appendTo(hidden);
});

The above adds the images to an element that belongs to the DOM, but since that div is not displayed, the images never show up.

An even better solution The best way to handle this, though, is to put all of the images in the document to begin with, and then use CSS to control visibility. In this case, you are not dynamically inserting and removing images at all, and the browser will handle all of the image loading. (Of course, in my particular circumstance, this was not an option -- thus the solution above.)