Wait for image to be loaded before going on

Jem picture Jem · Dec 27, 2011 · Viewed 49.8k times · Source

I'm developing a game using JavaScript and canvas. As the game loads, all images that will be used are being cached.

Observing the resource timeline, I see that the following code triggers an asynchronous request:

var sprite = new Image();
sprite.src = "sprites/sheet1.png";

The engine will keep executing, eventually beginning to draw and play the level. Images that are loaded after the first frame is painted might never appear due to clipping (i.e. not getting "dirty").

So I tested the following:

console.log("begin");
var sprite = new Image();
sprite.onload = function() { console.log('loaded!'); };
sprite.src = "sprites/sheet1.png";
console.log("end");

The resulting console outputs in the order they occur are:

  • begin
  • end
  • loaded!

I'm looking for a similar way to $.ajax with async: false to perform the loading. Can't figure out how... thanks in advance for you help! J.

Answer

ThiefMaster picture ThiefMaster · Dec 27, 2011

You shouldn't make anything synchronous (not even AJAX) calls but instead simply put your code in the appropriate callback:

function loadSprite(src, callback) {
    var sprite = new Image();
    sprite.onload = callback;
    sprite.src = src;
}

Then use it like this:

loadSprite('sprites/sheet1.png', function() {
    // code to be executed later
});

If you want to pass additional arguments, you can do it like this:

sprite.onload = function() {
    callback(whatever, args, you, have);
};

If you want to load multiple elements and need to wait for all of them to finish, consider using the jQuery deferred object:

function loadSprite(src) {
    var deferred = $.Deferred();
    var sprite = new Image();
    sprite.onload = function() {
        deferred.resolve();
    };
    sprite.src = src;
    return deferred.promise();
}

In the function loading the sprites, you do something like this:

var loaders = [];
loaders.push(loadSprite('1.png'));
loaders.push(loadSprite('2.png'));
loaders.push(loadSprite('3.png'));
$.when.apply(null, loaders).done(function() {
    // callback when everything was loaded
});

http://api.jquery.com/jQuery.when/