JavaScript 图片仅在刷新时加载

JavaScript Image only loads on refresh

我目前正在努力解决我的游戏引擎中一个非常烦人的问题... 我无法弄清楚为什么第一次加载页面时图像没有加载,为了使这项工作我必须刷新它。 这是我当前的代码:

纹理创建:

/**
 * @param {GLContext} context Context
 * @param {boolean} clamp Clamp
 * @param {Integer} filter Filter
 */
this.create = function(filename, context, filter, clamp) {    
    this.filename = filename;
    this.context = context;

    var gl = context.GL;

    this.id = gl.createTexture();
    this.id.image = new Image();
    var _this = this;

    this.id.image.onload = function() {
        gl.bindTexture(gl.TEXTURE_2D, _this.id);

        gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filter);
        gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filter);

        if (clamp) {
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
        } else {
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
        }

        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this);

        gl.bindTexture(gl.TEXTURE_2D, null);
        loaded = true;

    };
    this.id.image.src = filename;

    // ...
};

资源加载:

/**
 * Load all texture resources
 */
this.loadTextureResources = function() {
    for (var key in queue) {
        var i = queue[key];
        var tmpt = new Texture();               
        tmpt.create(i.filename, context, i.filter, i.clamp);
        this.resources[key] = tmpt;
    }
};

和游戏初始化:

/**
 * Start game
 */
this.start = function() {
    this.loadTextureResources();

    tree.create();
    if (typeof this.oncreate === "function") this.oncreate();

    setTimeout(this.gameloop, 500);
};

您还可以看到演示 Here and Here

(我几乎尽我所能,并花了 3 天时间试图解决这个问题...)

提前致谢...

在所有现代网络浏览器中,图像都是异步加载的,以提高速度。因此,只有在页面刷新后,您的图像才会加载得足够早,因为它们已经被缓存了。

首先尝试缓存您的图像,只有在它们被缓存后,才触发其余的逻辑。

图片缓存到浏览器后,下次使用时加载速度会更快。

要缓存图像,您所要做的就是将它们加载到浏览器中。

您可以像这样缓存图像:

function cacheImages(array)
{
    if (!cacheImages.list) {
        cacheImages.list = [];
    }
    var list = cacheImages.list;
    for (var i = 0; i < array.length; i++) {
        var img = new Image();
        img.onload = function() {
            var index = list.indexOf(this);
            if (index !== -1) {
                // remove image from the array once it's loaded
                // for memory consumption reasons
                list.splice(index, 1);
            }
        }
        list.push(img);
        img.src = array[i];
    }
}

cacheImages(["url1.jpg", "url2.jpg", "url3.jpg"]);

最终,随着时间的推移,浏览器缓存可能会填满并删除未使用的最旧内容。

因此,建议您始终尝试缓存,因为如果浏览器已经有图像,则不会再次保存它(如果浏览器足够聪明,通常不会保存重复的图像)。

图像加载是异步的。例如,如果需要几秒钟,图像的 'onload' 只会在几秒钟后被调用,而当前作用域中的代码会继续执行。您的示例似乎无法解决这个问题。当然,我没有仔细阅读您的示例链接的全部内容,所以我可能会弄错。

您可能最好让某个资产管理器为您处理此问题,并将整个绘图初始化包装在一个回调中,该回调仅在所有需要的资源加载完成后调用。

第二次这不是问题的原因是图像来自缓存,并且大多数浏览器(我认为 IE 是例外)一旦附加到资源就直接调用 onload 处理程序已加载。

顺便说一句,如果你有这样的问题,在服务器端重写一些缓冲脚本,故意延迟响应,这样你可以更好地看到效果。它对调试有很大帮助,例如一个简单的 PHP 脚本执行 sleep(3);,然后传递文件。当然,也可以使用浏览器的节流功能。