javascript - 为什么我的图像预加载方法有效?

标签 javascript arrays html5-canvas theory

我的问题

目标是确保在新游戏开始之前所有图像都已完全加载。我的第二个解决方案 (Fiddle B) 比我的第一个解决方案 (Fiddle A) 更一致、更准确地实现了这个目标。 为什么?

JSFIDDLE A

JSFIDDLE B

方法

这是我的两个 fiddle 解决方案对预加载图像的作用:

  • 游戏所需的所有 Assets 都有一组绝对图像 URLS
  • init() 函数有一个 for 循环,它为数组中的每个 URL 生成一个新的 Canvas Image()
  • 每个新创建的图像被插入另一个数组
  • 因此,我们现在有了包含 URL 字符串的第一个数组,以及包含“HTMLImageElement”对象的第二个数组

Fiddle B 与 Fiddle A 的不同之处在于它利用了“.onload”事件和一个计数器。这两个 fiddle 使用不同的方式检查是否所有图像资源都已加载:

Fiddle A:比较两个数组的长度。如果匹配,则开始游戏

for (var i = 0; i < allGameImageUrls.length; i++) {
        var img = new Image();
        img.src = allGameImageUrls[i];
        allGameImages.push(img);
        console.log(allGameImages.length);
        if (allGameImages.length >= allGameImageUrls.length) {
            setUpGame();
        } else {
            // images haven't loaded yet
            console.log('STILL LOADING');
            STAGE.fillText("Loading ...", 20, 400);
        }
    }

Fiddle B:将第二个数组长度与计数器变量进行比较。每次图像的“.onload”事件完成时,此计数器都会加 1。

for (var i = 0; i < allGameImageUrls.length; i++) {
    var img = new Image();
    img.onload = function () {
        assetCount++;
        console.log('assetCount = ' + assetCount);
        setUpGame();
    };
    img.src = allGameImageUrls[i];
    allGameImages.push(img);
}

我的问题扩展了

Fiddle A 经常(但并非总是)在正确加载完整图像 Assets 列表之前触发新游戏的开始,从而导致游戏错误。 Fiddle B 在允许新游戏开始之前始终加载所有图像 Assets 。这可以在写入 Canvas 的“完全加载”消息的两个 fiddle 中看到。

虽然我可以看到 Fiddle A 比 Fiddle B 更好,但我不明白为什么它更优越。并非所有与加载 HTMLImageElements 相关的教程都使用“.onload”,不使用它的教程似乎就足够了。

此外,我不明白为什么比较两个数组的长度不如将第二个数组长度与计数器进行比较准确。

我理解如何这两种解决方案有何不同,但我想知道为什么解决方案 B 比解决方案 A 更有效。

先前的研究

为了回答我自己的问题,这里只是我之前所做的一些研究示例。

  • An article on pre-loading images它没有任何对 .onload 事件的引用
  • this question 的公认解决方案不使用 .onload 事件,但它仍然有效
  • this other question 的公认解决方案与我的 Fiddle B 非常相似(虽然我发现它很晚)。然而,解决方案的解释并没有帮助我回答我自己的问题。

最佳答案

您正在比较两种截然不同的方法:顺序使用 for(这是不正确的)和基于事件。

图片下载是异步过程,所以当设置图片 src 属性时,浏览器开始下载它。然而,它可以非常快,特别是如果图像已经被浏览器下载并在内部缓存(事实上,它非常快)。因此,当下一次迭代开始时,它已经可用(或者,至少,几乎所有的迭代在循环结束时都可用)。但是,如果您清除缓存或使用隐身模式并从远程位置(而不是您的本地服务器)下载它们,那么繁荣! - 循环结束时根本没有下载图像。

另一种方法稍微好一点,但游戏是为下载的每个图像设置的,这可能不是所需要的。

考虑以下方法:

var length = allGameImageUrls.length,
    count = 0;

var i, img;

for (i = 0; i < length; i++) {
    img = new Image();
    img.onload = function () {
        count++;
        // count is increased on every callback
        // so if number of executed callbacks equals
        // the number of images then all the images
        // are downloaded
        if (count === length) {
            setUpGame();
        }
    };
    img.src = allGameImageUrls[i];
    allGameImages.push(img);
} 

唯一的缺点是如果其中一张图片不存在,游戏将永远不会开始,因此您需要使用超时来解决它。

关于javascript - 为什么我的图像预加载方法有效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25775572/

相关文章:

javascript - 适用于 POST 的方法不适用于 AJAX。但为什么?

javascript - 不使用 ajax 或表单发布 JSON 数据

javascript - Mongoose 删除文档中的数组元素

html - 在隐藏的 html5 canvas 元素中绘制不起作用

javascript - 单击一个 anchor 时触发单击另一个 anchor

javascript - 意外的 token 提供者

python - 比较列表理解和显式循环(3 个数组生成器比 1 个 for 循环更快)

java将数组的值更改为null的方法

javascript - 在不使用 Canvas 的情况下在 JavaScript 中调整 Base-64 图像的大小

javascript - 彼此上方的两个 Canvas 返回不同的 x,y 坐标