Wait for image to be loaded before going on

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.


Solution 1:

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/

Solution 2:

This question is old, but there is a way to do this without requiring jquery, OR freezing the browser.

In image1.onLoad, make it load image2.
In image2.onLoad, make it load image3.
In image3.onLoad, make it load image4.
....
In imagen.onLoad make it load your main function.

I'm not sure if this is the entirely BEST way to do it, but it's better than freezing the browser, at least.
You are able to also load all of your audio files or whatever other resources you need, or any other javascript you need to run.

Freezing the browser is not required