JavaScript Image only loads on refresh

2019-05-27 11:59发布

I'm currently struggling with a very annoying problem on my game engine... I can't figure out why the images are not loading on the first time the page loads, and to make this work I have to refresh it. Here's my current code:

Texture creation:

/**
 * @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;

    // ...
};

Resource loading:

/**
 * 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;
    }
};

And Game initialization:

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

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

    setTimeout(this.gameloop, 500);
};

You can also see a demo Here and Here

(I tried doing pretty much everything I could, and spent 3 days trying to fix this...)

Thanks in advance...

2条回答
\"骚年 ilove
2楼-- · 2019-05-27 12:12

The image loading is asynchronous. If it takes several seconds, for example, the 'onload' of the image only gets called after several seconds, while the code in your current scopes continues executing. Your example doesn't seem to handle that. Granted, I did not plough through the entirety of your example links, so I might be mistaken.

You'd probably be best off having some asset manager that handles this for you and wrap the entire drawing initialization in one callback that only gets called after all needed resources are done loading.

The reason that the second time this isn't an issue is that the image comes from cache, and most browsers (I think IE is the exception) directly call the onload handler as soon as it's attached to a resource that was already loaded.

By the way, if you have issues like this, have some rewrite buffer script at the server side delay the response deliberately so you can see the effect better. It helps debugging a lot, for example a simple PHP script doing a sleep(3); and then a passthru of the file. Or use throttling capabilities of your browser, of course.

查看更多
别忘想泡老子
3楼-- · 2019-05-27 12:30

In all modern web browsers, images load asynchronously, for speed purposes. So only after a page refresh your images are loading early enough because they are already cached.

Try to cache your images first, and only after they are cached, trigger the rest of your logic.

Once an image has been cached into the browser, it will load much faster the next time it is used.

To cache images, all you have to do is load them into the browser.

You can cache images like this:

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"]);

Eventually over time, the browser cache may fill up and delete the oldest things that haven't been used.

So, it is recomended that you always try to cache, because if the browser has the image already, it wont save it again (normally browsers do not save duplicates if they are clever enough).

查看更多
登录 后发表回答