views:

1124

answers:

5

I don't want to know a way to preload images, I found much on the net, but I want to know how it works. How is javascript able to preload images? I mean, I tried a snippet from here, and even if it works, it doesn't seem to preload images.

When I check firebug, I can see that the image is loaded twice, once while the preloading, another time when displaying it!

To improve this code I'd like to know how it works.

Here is what i do:

 function preload(arrayOfImages) {
        $(arrayOfImages).each(function(){
         $('<img/>')[0].src = this;
         //(new Image()).src = this;
         alert(this +'  &&   ' + i++);

        });
    }

then i do something like that:

preloader = function() {
    preload(myImages);
}

$(document).ready(preloader);

Here is how i display/add the image :

$("li.works").click(function() {
       $("#viewer").children().empty();
       $('#viewer').children().append('<img src=\'images/ref/'+this.firstChild.id+'.jpg\' alt="'+this.firstChild.id+'" \/>')
          $("#viewer").children().fadeIn();
+5  A: 

Your basic Javascript preloader does this:

var image = new Image();
image.src = '/path/to/the/image.jpg';

The way it works is simply by creating a new Image object and setting the src of it, the browser is going to go grab the image. We're not adding this particular image to the browser, but when the time comes to show the image in the page via whatever method we have setup, the browser will already have it in its cache and will not go fetch it again. I can't really tell you why whatever you have isn't working this way without looking at the code, though.

One interesting gotcha that is discussed in this question is what happens when you have an array of images and try preloading them all by using the same Image object:

var images = ['image1.jpg','image2.jpg'];
var image = new Image();
for(var x = 0; x < images.length; x++) {
    image.src = images[x];
}

This will only preload the last image as the rest will not have time to preload before the loop comes around again to change the source of the object. View an example of this. You should be able to instantly see the second image once you click on the button, but the first one will have to load as it didn't get a chance to preload when you try to view it.

As such, the proper way to do many at once would be:

var images = ['image1.jpg','image2.jpg'];
for(var x = 0; x < images.length; x++) {
    var image = new Image();
    image.src = images[x];
}
Paolo Bergantino
i think my code is very to similar to yours (i edited my question to add it)But Firebug is still showing me that images is loaded each times the image has to be displayed
Boris Guéry
+1  A: 

It just involves making a new DOM image object and setting the src attribute. Nothing clever and AFAIK, it has always worked for me.

Is it possible the second "load" firebug is showing you is it loading it from cache?

Oli
I just tested it and it doesn't show a load on this page (http://www.rootspot.com/stackoverflow/preload.php) when I click on the cached image.
Paolo Bergantino
+1  A: 

The index on the loop is only looking at the first image. Change it to use the index:

function preload(arrayOfImages) {
    $(arrayOfImages).each(function(i){   // Note the argument
        $('<img/>')[i].src = this;    // Note the i
        //(new Image()).src = this;
        alert(this +'  &&   ' + i++);

    });
}

Edit: In retrospect, this was wrong and I can see you're trying to create image elements. I don't understand why the index is there at all, there need not be an index. I think the function should look like this:

function preload(arrayOfImages) {
    $(arrayOfImages).each(function () {
        $('<img/>').attr('src', this);
    });
}

And to instantiate it, why not just do this:

$(function () {    // Equivalent to $(document).ready()
    preload(myImages);
});

JavaScript image preloading works because when a DOM element that contains an image is created, the image is downloaded and cached. Even if another request is made when the image is actually rendered from the HTML, the server will send back a 304 (not changed), and the browser will simply load the image from its cache.

Paolo suggests using the following notation to create an image object:

var image = new Image();

While this will work, the DOM-compliant way of doing this is:

var image = document.createElement('img');
image.setAttribute('src', 'path/to/image.jpg');

Which is the way it is being done in the script, except it's using jQuery's HTML string literal syntax to do it. Additionally, most modern browsers offer compatibility with the Image() constructor by simply calling DOM-standard methods. For example, if you open up the Google Chrome JavaScript console and type Image, this is what you'll get:

function Image() {
    return document.createElementNS('http://www.w3.org/1999/xhtml', 'img');
}

Chrome merely uses the native DOM methods to create an image element.

Andrew Noyes
What browser will choke on new Image()? Also, the initial suggestion of changing 0 to i is not valid. What he is doing by doing that is directly accessing the DOM element that he just created, which jQuery keeps in [0] in that case.
Paolo Bergantino
I'm not aware of any browsers that choke on it, but the DOM is designed to be language independent. Depending on the implementation, the native implementation the browser uses may not be the DOM.
Andrew Noyes
+1  A: 

You may be confused by the concept of "preloading". If you have a bunch of images in your HTML with <img src="...">, they cannot be preloaded with Javascript, they just load with the page.

Preloading images with Javascript is about loading images not already in the document source, then displaying them later. They are loaded after the page has rendered for the first time. They are preloaded in order to eliminate/minimize loading time when it comes to making them appear, for example when changing an image on mouse rollover.

For most applications, it is usually better practice to use "CSS sprites" as a form of preloading, in lieu of Javascript. SO should have a ton of questions on this.

DisgruntledGoat
+1 - I didn't consider perhaps he was just trying to preload images that were initially in the document. I certainly expect that to give off two requests.
Paolo Bergantino
A: 

I wrote a javascript image preloader awhile ago. I have an explanation on my site as to how each browser handles them and what problems you run into.

http://blog.152.org/2008/01/javascript-image-preloader.html

metric152