speedwell
speedwell

Reputation: 655

Accidental recursion using fetch() to load a texture

I am trying to use the fetch statement to load a local image and use it in my (three.js) application. The way it's set up now, I get an infinite loop and I don't know why.

It's a large application so I pulled the relevant fragment out here:

var mesh;

function fetch_img(filename) {

    fetch(filename).then(function(response) {

        if (response.ok) {

            return response.blob();
        }
        throw new Error('Network response was an error.');

    }).then(function(blob) {

        mesh.material.map.image.src = URL.createObjectURL(blob);
        mesh.material.map.needsUpdate = true;

    }).catch(function(error) {

        console.log('Fetch failed because: ' + error.message);
    });

}

function start() {

    var material = new THREE.MeshBasicMaterial({

        map: new THREE.TextureLoader().load('loading.jpg', function(texture) {

            mesh = new THREE.Mesh(geometry, material);
            scene.add(mesh);

            fetch_img('test1.jpg');
        })
    });
}

The idea being that I use a 'loading' image and then when the scene is created and that is loaded, I load the real image by calling fetch_img(). Ultimately I'll be calling fetch_img() from a number of places based on user input.

I expect it's something I've done wrong trying to understand JavaScript Promises - can someone point me in the right direction?

Upvotes: 0

Views: 201

Answers (1)

TheJim01
TheJim01

Reputation: 8876

Here is what is happening:

Inside THREE.TextureLoader, it's using THREE.ImageLoader. THREE.ImageLoader creates an img element, and assigns an onload event listener to it. It then sets the img.src to the URL you provide it.

When you give the image.src property a new value, that event gets fired, and goes to its handler, which is still assigned to the anonymous function you gave it in your THREE.TextureLoader definition.

The rest is recusrively history.

To fix it, create a new image, assign the URL to its src property, then replace the whole map.image with the new image.

Upvotes: 2

Related Questions