Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fire an event after preloading images

This is the code I use to preload images, I'm not sure if it's the best one. My question is, how can I fire and event, for an example alert(); dialog after is has finished loading all the images?

var preload = ["a.gif", "b.gif", "c.gif"];
    var images = [];
    for (i = 0; i < preload.length; i++) {
        images[i] = new Image();
        images[i].src = preload[i];
    }
like image 781
Badr Hari Avatar asked Apr 11 '11 15:04

Badr Hari


4 Answers

You can use the new "$.Deferred" if you like:

var preload = ["a.gif", "b.gif", "c.gif"];
var promises = [];
for (var i = 0; i < preload.length; i++) {
    (function(url, promise) {
        var img = new Image();
        img.onload = function() {
          promise.resolve();
        };
        img.src = url;
    })(preload[i], promises[i] = $.Deferred());
}
$.when.apply($, promises).done(function() {
  alert("All images ready sir!");
});

Might be a little risky to leave the Image objects floating around, but if so that could be fixed easily by shifting the closure. edit in fact I'll change it myself because it's bugging me :-)

like image 100
Pointy Avatar answered Sep 23 '22 04:09

Pointy


Since your tags include jQuery, here's what I would do in jQuery, with heavy inspiration from this related answer:

function preloadImages(images, callback) {
    var count = images.length;
    if(count === 0) {
        callback();
    }
    var loaded = 0;
    $.each(images, function(index, image) {
        $('<img>').attr('src', image).on('load', function() { // the first argument could also be 'load error abort' if you wanted to *always* execute the callback
            loaded++;
            if (loaded === count) {
                callback();
            }
        });
    });
};

// use whatever callback you really want as the argument
preloadImages(["a.gif", "b.gif", "c.gif"], function() {
    alert("DONE");
});

This relies on the callback to jQuery's load function.

I wouldn't use the related answer simply because I don't like mucking around with Javascript's built-in prototypes.

like image 32
justkt Avatar answered Sep 23 '22 04:09

justkt


I've seen something used to correct behavior on Masonry nice jQuery plugin (a plugin used to make nice layout composition on pages). This plugin had problems with blocks containing images and should delay his work when the images are loaded.

First solution is to delay on the onLoad event instead of document.ready. But this event can be quite long to wait for. So they use jquery.imagesloaded.js which can detect that all images in a div are loaded; especially this very short and nice code can handle cached images which does not fire the load event sometimes.

like image 21
regilero Avatar answered Sep 21 '22 04:09

regilero


Today I needed to preload images and execute some code only after all images are loaded, but without jQuery and using Ionic2/Typescript2. Here's my solution:

// Pure Javascript Version
function loadImages(arrImagesSrc) {
    return new Promise(function (resolve, reject) {
        var arrImages = [];
        function _loadImage(src, arr) {
            var img = new Image();
            img.onload = function () { arr.push([src, img]); };
            img.onerror = function () { arr.push([src, null]); };

            img.src = src;
        }
        arrImagesSrc.forEach(function (src) {
            _loadImage(src, arrImages);
        });
        var interval_id = setInterval(function () {
            if (arrImages.length == arrImagesSrc.length) {
                clearInterval(interval_id);
                resolve(arrImages);
            }
        }, 100);
    });
}

// Ionic2 version
private loadImages(arrImagesSrc: Array<string>): Promise<Array<any>> {
    return new Promise((resolve, reject) => {
      ...
      function _loadImage(src: string, arr: Array<any>) {
        ...
      }
      ...
 }

You can use like this. Problematic url returns 'null'.

loadImages(['https://cdn2.iconfinder.com/data/icons/nodejs-1/512/nodejs-512.png', 'http://foo_url'])
.then(function(arr) {
   console.log('[???]', arr); 
})
like image 27
Roque Avatar answered Sep 21 '22 04:09

Roque