How to deal with async loader?

If have a problem when I use a loader for one of my function.
Here’s the code I writed:

export function loadSTL(filepath, colorRGB) {
let inst;

// Load STL file
const loader = new STLLoader();
loader.load(
   filepath,
  (geometry) => { inst = STLToInstance(geometry, colorRGB); },
);

return inst;
}

The purpose of this is to return the var inst when the load is done.
Unfortunately, the function return null so I thought that the function return before the end of the load.

Does someone have an idea of what can I do for this?

What about this

export function loadSTL(filepath, colorRGB) {
    let inst

    // Load STL file
    const loader = new STLLoader()
    loader.load(
        filepath,
        (geometry) => { 
            inst = STLToInstance(geometry, colorRGB)
            return inst;
        },
    )
}

The function still return undefined. I don’t find a way to “wait” until the end of the load.

Couldn’t you use the new Loader.loadAsync() method? Checkout how this method is used in the following example:

https://threejs.org/examples/webgl_tonemapping

You should be able to use it with STLLoader, too.

3 Likes

Sounds like a similar problem that I had which was solved here:

Check the comment that was marked as solution

The only way to do exactly what you’d like to do is using async/await:

async function loadSomething() {
  return new Promise((resolve) => {
    const loader = new STLLoader();

    loader.load(
      filepath,
      (geometry) => resolve(STLToInstance(geometry, colorRGB)),
      () => resolve()
    });
  });
};

// Async / await require outer context to be an `async` function
(async function main() {
  const model = await loadSomething();

  console.log(model) // <- valid STL model instead of null / undefined

  scene.add(model);
})();

Non-async/await alternative that does exactly the same would be:

export function loadSTL(filepath, colorRGB) {
  return new Promise((resolve) => {
    const loader = new STLLoader();

    loader.load(
      filepath,
      (geometry) => resolve(STLToInstance(geometry, colorRGB)),
      () => resolve()
    });
  });
}

loadSTL.then((model) => {
  // Continue with model loaded
});

Loader.loadAsync() @Mugen87 mentioned above does the Promise approach.

Edit: Small fiddle with sample async/await https://jsfiddle.net/bur54veo/

2 Likes

I spent some time to find how to use this, maybe it will be useful for someone:

var gltfLoader = new THREE.GLTFLoader();
var result = await gltfLoader.loadAsync("car/scene.gltf");
...

I looked at the example and didn’t find “loadAsync” in the code. No hits when I entered “loadAsync” into the examples search either. I would be great if there was a good example of how to use this feature - assuming it’s still the latest-greatest solution.

Where did you look?

It’s documented here:
https://threejs.org/docs/index.html#api/en/loaders/Loader.loadAsync

Also one can use it as such:

new Loader.loadAsync('foo').then((result)=>{
  //do something
})

I’ve got a write up here (4 minute read)
Discusses and demonstrates why you might want to use LoadAsync
It also demonstrates using Async/Await, Promise.All() & LoadAsync together
Honestly, I’m just happy to load dependent objects using nested callbacks

1 Like

That’s a super helpful article. Thanks for writing it!

The reason that nested callbacks don’t work well for me is that I want to do a bunch of additional things to the model, such as scale it, color it, etc. It’s quite tricky to pass additional parameters into the callback to describe the additional work you want to do. While it is possible by making a separate function that returns the desired callback function, it takes a while to get this code to do what you want, its harder to debug, and what you end up with is hard for someone who’s not experienced with javascript to understand.