Reputation: 3880
The list below is part of a frogger game from Udacity's object-oriented javascript course's final project. It is given by Udacity, The purpose of following code is to build a simple image loading cache. My question is after the list. Git: https://github.com/udacity/frontend-nanodegree-arcade-game
(function() {
var resourceCache = {};
var loading = [];
var readyCallbacks = [];
function load(urlOrArr) {
if(urlOrArr instanceof Array) {
urlOrArr.forEach(function(url) {
_load(url);
});
} else {
_load(urlOrArr);
}
}
function _load(url) {
if(resourceCache[url]) {
return resourceCache[url];
} else {
var img = new Image();
img.onload = function() {
resourceCache[url] = img;
if(isReady()) {
readyCallbacks.forEach(function(func) { func(); });
}
};
resourceCache[url] = false;
img.src = url;
}
}
function get(url) {
return resourceCache[url];
}
function isReady() {
var ready = true;
for(var k in resourceCache) {
if(resourceCache.hasOwnProperty(k) &&
!resourceCache[k]) {
ready = false;
}
}
return ready;
}
function onReady(func) {
readyCallbacks.push(func);
}
window.Resources = {
load: load,
get: get,
onReady: onReady,
isReady: isReady
};
})();
Resources.load([
'images/stone-block.png',
'images/water-block.png',
'images/grass-block.png',
'images/enemy-bug.png',
'images/char-boy.png'
]);
Resources.onReady(init);//init function is to start the game
My question is about this line
img.src = url
I've thought that after this line, the image will be loaded immediately and the img.onload will be fired right away. I think If this was the case, then:
Inside the img.onload() function, since there is only one property in resourceCache at this time and it has been set to 'img', the isReady() call will return true, and readyCallbacks will be called. However, since the .onReady() function hasn't been executed(the program is still in the Resources.load() function), there is nothing in readyCallbacks at this time, so the program will do nothing, but later on, since img.onload has been fired, it will not be fired again, thus after Resources.onReady() is executed and the init() function is inserted into readyCallbacks, it will not be invoked, so the game won't be initiated.
I was reading the code, when I got here I couldn't understand. After I run the code step by step, I find out that it actually takes time for the images to be loaded, even though they are all local. Using performance.now(), I found that it takes a picture about 0.5ms to be loaded, by then the for loop in which _load() is called has completed, and the 2nd and 3rd resourceCache's properties have been set to false, so isReady() won't evaluate to true, and the code will behave normally. And if there is only one image to load, then before the image is loaded, the .onReady() ( which is after Resource.load() ) will have been called and init() will have been inserted into readyCallback, and the code will work too.
If there is nothing wrong with the above analysis of mine, then there is one thing I still don't understand: can we really rely on this image loading time being more than other codes' execution time? what if the images are really small and img.onload fires before another property of rescourceCache is set to 'false' or the readyCallback has been set up? If so the code won't work.
When I think further, I can't understand why we have to put
if (isReady()) {
readyCallbacks.forEach(function (func) {
func();
});
}
in the img.onload() function, which makes it being executed multiple times when we are to load multiple images. Can we just put it after the .load() call in the ? After all, its purpose is to check if all the images have been loaded.
Upvotes: 0
Views: 818
Reputation: 1674
The img.onload
callback is placed in the execution queue and not executed, at the earliest, until the rest of the code has run to completion.
The isReady
function is called multiple times because that function will only return true
if all the images have finished downloading. It needs to be run after each image because there's no way to know which image will be the last one to finish loading and thereby trigger the callbacks.
Upvotes: 1