jQuery callback on image load (even when the image is cached)

My simple solution, it doesn't need any external plugin and for common cases should be enough:

/**
 * Trigger a callback when the selected images are loaded:
 * @param {String} selector
 * @param {Function} callback
  */
var onImgLoad = function(selector, callback){
    $(selector).each(function(){
        if (this.complete || /*for IE 10-*/ $(this).height() > 0) {
            callback.apply(this);
        }
        else {
            $(this).on('load', function(){
                callback.apply(this);
            });
        }
    });
};

use it like this:

onImgLoad('img', function(){
    // do stuff
});

for example, to fade in your images on load you can do:

$('img').hide();
onImgLoad('img', function(){
    $(this).fadeIn(700);
});

Or as alternative, if you prefer a jquery plugin-like approach:

/**
 * Trigger a callback when 'this' image is loaded:
 * @param {Function} callback
 */
(function($){
    $.fn.imgLoad = function(callback) {
        return this.each(function() {
            if (callback) {
                if (this.complete || /*for IE 10-*/ $(this).height() > 0) {
                    callback.apply(this);
                }
                else {
                    $(this).on('load', function(){
                        callback.apply(this);
                    });
                }
            }
        });
    };
})(jQuery);

and use it in this way:

$('img').imgLoad(function(){
    // do stuff
});

for example:

$('img').hide().imgLoad(function(){
    $(this).fadeIn(700);
});

If the src is already set, then the event is firing in the cached case, before you even get the event handler bound. To fix this, you can loop through checking and triggering the event based off .complete, like this:

$("img").one("load", function() {
  // do stuff
}).each(function() {
  if(this.complete) {
      $(this).load(); // For jQuery < 3.0 
      // $(this).trigger('load'); // For jQuery >= 3.0 
  }
});

Note the change from .bind() to .one() so the event handler doesn't run twice.


Can I suggest that you reload it into a non-DOM image object? If it's cached, this will take no time at all, and the onload will still fire. If it isn't cached, it will fire the onload when the image is loaded, which should be the same time as the DOM version of the image finishes loading.

Javascript:

$(document).ready(function() {
    var tmpImg = new Image() ;
    tmpImg.src = $('#img').attr('src') ;
    tmpImg.onload = function() {
        // Run onload code.
    } ;
}) ;

Updated (to handle multiple images and with correctly ordered onload attachment):

$(document).ready(function() {
    var imageLoaded = function() {
        // Run onload code.
    }
    $('#img').each(function() {
        var tmpImg = new Image() ;
        tmpImg.onload = imageLoaded ;
        tmpImg.src = $(this).attr('src') ;
    }) ;
}) ;