8

I have a container that has some images inside, I want to listen to the event of every image finish loaded.

eg)

<div id="container">
     <img src="..." />
     <img src="..." />
     <img src="..." />
     <img src="..." />
</div>

I should got 4 times of the "image loaded" event. How to do this?

Bin Chen
  • 61,507
  • 53
  • 142
  • 183

3 Answers3

15

The only reliable way to listen to the load events of images that are in your HTML source is to specify an onload handler in the HTML:

<div id="container">
     <img onload="imageLoad()" src="..." />
     <img onload="imageLoad()" src="..." />
     <img onload="imageLoad()" src="..." />
     <img onload="imageLoad()" src="..." />
</div>

This is because you can't attach event handlers to images in your page HTML until the image tags are loaded themselves (so they are present in the DOM). Once those images tags are loaded, the source of the image is already being loaded and, if it's available quickly (like in the browser cache), it might get loaded before you can attach the event handler. Thus, at best you can't be sure it will work and at worst, it won't work. In any case, it may not be reliable.

Or, if you just want to know when all images are loaded in the page, you can use the load event for the whole document. In jQuery, you can do that with $(window).load(fn).

Or, you can attach the load events and then check to see if any of the images are already loaded and count those as loaded. I'm not sure if there's an official standard way to see if an image is already loaded or not, but I have found that if there is no width set in the HTML and there is a non-zero value for the .width attribute, then the image must be loaded because it's the loading of the image that causes the non-zero width value to get set.

Your other option is to not put the images into the HTML of your page and add them dynamically and you can assign load handlers when you create the images before you assign the .src attribute.


Testing the Issue

To explore this a little further, I built a test bed in jsFiddle: http://jsfiddle.net/jfriend00/7FjdJ/. It has four images in it and reports how many images are already loaded when $(document).ready() fires and reports how many images fire the .load() event. The results show a variation in behavior from one browser to the next.

In Chrome 15, if the images are already in the cache, I get no load events and all four are already loaded when $(document).ready() fires. The behavior appears to vary depending upon how much content there is in the page after the images.

In Safari 5, the first time I load the page, it reports 4 load events, 0 images already loaded. The second time I load the page, it reports 0 load events, 4 images already loaded.

In IE9, the images always appear to already be loaded and no load events fire, whether cached or not.

In Firefox 7, the first time I load the page, I get 0 load events and 4 images already loaded. The next time I load the page, I get 4 load events and 4 images already loaded.

Also, since this is a timing issue, it wouldn't surprise me if the behavior depends upon the size of the images and speed of loading them as slow loading images could cause load events to fire late enough to be seen. It may also depend upon how much content there is to load in the page after the images (e.g. how much work is to be done before document.ready can be fired).

So, my conclusion is that the behavior of the .load() event handler when installed after the image has started loading is inconsistent from one browser to the next and from one situation to the next, thus you cannot count on it without other code to mitigate those differences (checking to see if the images are already loaded).


There is another approach. You can install the event handlers after the DOM has loaded and when installing the event handler, you can check if the image is already loaded. Here's one way to do that:

<div id="container">
     <img src="..." />
     <img src="..." />
     <img src="..." />
     <img src="..." />
</div>

<script>
$("#container img").each(function() {
    if (this.complete) {
        // this image already loaded
        // do whatever you would do when it was loaded
    } else {
        $(this).on('load', function() {
            // image now loaded
        });
    }
}); 

Working demo: http://jsfiddle.net/jfriend00/6Cq4y/

What you will find in the demo is that if your browser cache has never seen this jsFiddle, then if will show 4 load events, but if the browser cache has already seen this jsFiddle, then it will get no load events and all the images will already be loaded by the time your javascript runs and it will see they are loaded in the if (this.complete) branch of the code.

j08691
  • 204,283
  • 31
  • 260
  • 272
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • Added a second approach that checks `this.complete` and doesn't require putting an onload handler into the HTML. – jfriend00 Jul 26 '14 at 02:03
4

Using jQuery:

$('#container img').load(function() {
    alert('image loaded');
});

Using simple javascript you can use the onload attribute:

<img src="yourimage.gif" onload="loadImage()" />

The function will be:

function loadImage() {
    alert("image loaded");
}
I.G. Pascual
  • 5,818
  • 5
  • 42
  • 58
  • It's a little funny that this answer and mine are virtually identical, yet mine got a downvote :-) – Pointy Dec 20 '11 at 04:18
  • makes me angry you thinking I downvoted it... talk with jfriend00, he's a bit more fussy with this. We have a discussion in your answer... – I.G. Pascual Dec 20 '11 at 04:19
  • ?? I don't have any idea who downvoted me ... I certainly didn't intend to blame you! – Pointy Dec 20 '11 at 13:44
2
$('#container img').load(function() {
  // ...
});

You'll want to set that up pretty close to the point at which the elements are introduced to the DOM, or else they might be loaded before you manage to attach the event handler.

Pointy
  • 405,095
  • 59
  • 585
  • 614
  • 2
    This is not guaranteed to be reliable because an image coming from the cache can very easily be loaded before you can run this javascript. – jfriend00 Dec 20 '11 at 02:21
  • @jfriend00 he's not talking about loading images dynamically, just listening to onload image's event – I.G. Pascual Dec 20 '11 at 02:23
  • @Nacho - It looks to me like he's trying to know when images in the page's HTML are loaded. You can't do it reliably by installing an event handler after the DOM has loaded. You have to get the event handler installed either in the HTML or before `.src` is set. If the image is in the page HTML, then you have to put the event handler in the HTML too. – jfriend00 Dec 20 '11 at 03:31
  • @jfriend00 well, you're right, but I'm assuming he's using that script inside the `head` element, but I may be assuming too much :S – I.G. Pascual Dec 20 '11 at 03:36
  • @Nacho - You can't run it inside the HEAD element. The DOM objects aren't there yet to install event handlers on. – jfriend00 Dec 20 '11 at 03:37
  • @jfriend00 how about $(function(){ ?... still, I'm not going to discuss this things with you, let Bin Chen talk, and we'll know the better approach – I.G. Pascual Dec 20 '11 at 03:44
  • @Nacho - that's the same as `$(document).ready(fn)`. The DOM is already loaded when that fires and images may or may not already be loaded. Cached images are probably already loaded (depends on browser). If you want to know when all images in the page are loaded, one can use $(window).load(fn)`. – jfriend00 Dec 20 '11 at 03:49
  • @jfriend00 does that happen with all browsers? – I.G. Pascual Dec 20 '11 at 03:53
  • @jfriend00 yes I know - that's why I said it's important to bind it pretty closely to the element. Really, the best thing to do is do it in script code that grabs the image before the HTML is even there, but my (vague) understanding is that it's possible that old IE versions even then might skip the "load" event. – Pointy Dec 20 '11 at 04:17
  • Whoever downvoted me might want to check out the other upvoted answer to this question :-) – Pointy Dec 20 '11 at 04:18
  • FYI, I added a working test case to the end of my answer that illustrates the issues with installing the `.load()` handler after the page has loaded. – jfriend00 Dec 20 '11 at 07:20
  • @jfriend00 yes that's why I said that the the code should run "close to the point at which the elements are introduced to the DOM". Even that won't guarantee it'll work however, as you say. As far as I know the only other way to really guarantee that a "load" handler for an `` runs is to do it completely in JavaScript: create an "Image" instance (or a DOM element I guess), establish the handler, and then set the "src" property. – Pointy Dec 20 '11 at 13:47