下面的列表是Udacity面向对象的javascript课程最终项目的蛙游戏的一部分。它由Udacity给出,以下代码的目的是构建一个简单的图像加载缓存。我的问题是在列表之后。 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
我的问题是关于这一行
img.src = url
我认为在此行之后,图像将立即加载,img.onload将立即被触发。我想如果是这样的话,那么:
在img.onload()函数中,由于此时resourceCache中只有一个属性并且已设置为' img',isReady()调用将返回true,而readyCallbacks将返回叫做。但是,由于.onReady()函数尚未执行(程序仍在Resources.load()函数中),此时readyCallbacks中没有任何内容,因此程序将不执行任何操作,但稍后,因为img.onload已被触发,它不会被再次触发,因此在执行Resources.onReady()并将init()函数插入readyCallbacks之后,它将不会被调用,因此游戏不会被激活被启动。
我正在阅读代码,当我到达这里时我无法理解。在我逐步运行代码之后,我发现实际上需要花费时间来加载图像,即使它们都是本地的。使用performance.now(),我发现它需要加载大约0.5ms的图片,然后调用_load()的for循环已经完成,并且第二个和第三个resourceCache的属性已经设置为false,所以isReady()不会评估为true,代码将正常运行。如果只加载一个图像,那么在加载图像之前,将调用.onReady()(在Resource.load()之后)并且init()将被插入到readyCallback中,并且代码也会奏效。
如果对我的上述分析没有任何问题,那么有一件事我还是不明白:我们真的可以依赖这个图像加载时间比其他代码更多吗?执行时间处理时间?如果图像非常小并且在rescourceCache的另一个属性被设置为' false'之前触发img.onload会怎么样?还是设置了readyCallback?如果是这样,代码就不会起作用。
当我进一步思考时,我无法理解为什么要提出
if (isReady()) {
readyCallbacks.forEach(function (func) {
func();
});
}
img.onload()函数中的,当我们要加载多个图像时,它会多次执行。我们可以把它放在.load()调用之后吗?毕竟,其目的是检查是否已加载所有图像。
答案 0 :(得分:1)
img.onload
回调放在执行队列中,最早不执行,直到其余代码运行完毕。
isReady
函数被多次调用,因为如果所有图像都已完成下载,该函数将仅返回true
。它需要在每个图像之后运行,因为无法知道哪个图像将是最后一个完成加载的图像,从而触发回调。