Wait for object loader

Ok,
I have spent so much time, it’s pathetic but here goes. I have been reading promise wait and async in google, but yet no luck.

What I am trying to do is this. I want to preload my models before playing the scene. What I have done with images, videos, sprite, etc have all worked perfect. What I do is go load them and move then to crazy y position like 10,000. Then when I need them in scene I just change y position, and tada, they appear. When I try same with models, it does not wait till model is loaded, it simply returns instantly. I do Not want that to happen. I need it to wait till complete. Now I have tried es 6 promise wait, but that returns immediately too. I need a way to wait.

Say for example this is my main list of commands

LoadImage();
LoadSprite();
LoadModel();
LoadImage();

Now load image loads before a model because of size, I need to make it wait till model loaded.

I use promise to make it go through this list and works fine except LoadModel().

I don’t even know if there is a way to do this, but willing to try Anything…

Thanks,
Jeff

Have you read the docs for the respective loaders you need? All Three.js loaders have an onLoad callback that gets triggered once the asset has finished loading. For example:

const modelLoader = new GLTFLoader();
modelLoader.load(
    "my3DModel.gltf", 
    function(gltf) {
        // This function is called once your model has finished loading
        // So you can do whatever you want
        camera.position.y = 10000;
    }
);

Thanks but that’s not what I need, that is simply starting a off task that returns right away and resolvers itself later then you can pass more code. What I need is the loader to wait till the onload has returned then continue. Make sense? Trust me I tried every example I could find :crazy_face:

Something like using a while function to wait till it gets onload but that just seems to lock up the browser

Unless you’re able to use newer JavaScript features like async/await, network requests don’t prevent execution of the next line of code. Synchronous requests, which completely freeze the page, are possible but strongly deprecated.

Most three.js users rely on callbacks, as @marquizzo suggests. This does require structuring your code so that code after the .load(...) line does not depend on the result of the loading operation.

Another alternative is async/await. It’s a newer feature and less familiar to many JS devs, but it does basically what you want:

const result = await loader.loadAsync('model.glb');

In this example the keyword ‘await’ is critical, and the function where this code runs must itself be an async function.

You can find longer explanations of the various options (callbacks, promises, async/await) in this article:

https://eloquentjavascript.net/11_async.html

Don,
I tried the loadasync but it seemed to return right away as well. I tried loadmanager and I thought that might do it, but on loading a gftl file, it loaded the first texture then returned and then loaded other textures and gftl and bin afterwards, so I am at a loss. Perhaps the other calls are not working either but we’re so fast, it just seemed like they did.
Do you think a fetch call would be useful? Or just another failed way to preload everything

honestly I not really sure what you are trying to do. (I not speak English)
Maybe something like
setTimeout(()=>resolve(), 2000);
?
:3 :3 :3

or maybe a boolean that pass to true on your last function. and that boolean activate the render and once is active it can pass your model visibility to true?

@MrBodean it sounds like you have more code involved here than what’s in your post, can you share something we can look at? If you have nested functions, they need to all use async await, or things just continue without waiting for requests to complete. fetch() will work the same way.

async function LoadImage () {
  const result = await loader.loadAsync(...);
  return result;
}
async function LoadModel () {
  const result = await loader.loadAsync(...);
  return result;
}

const image = await LoadImage();
const model = await LoadModel();

Thanks Don and to everyone else for their feedback. It’s so nice to have a place you can bounce ideas off of so many people.

Well as I expected, none of the suggestions worked. I had tried all or at least some already was just hoping for a different outcome :slight_smile:

But GOOD News, I did figure a way to do it. The preload was a rather new part of my project so it was not too hard to change my other code. What I ended up doing was using a setinterval at the end and placed 2 varibles one PreObject and PreTotal. Then in the subrountines, I put a PreTotal++ and in the onload I put a PreObject, then in the setinterval I put a if (PreObject == PreTotal) then do the next part of code I moved to a subroutine as well.

Its working as I wanted. I think I will go back into my other subroutines for images, videos, sprties etc and do them the same way, then I can make sure ALL items are already loaded before I play the scene, so a few more tweeks but I think this will work perfectly.

Sorry I could not put a piece of code up for example, my project is so huge, its hard to pull a small examples out when something fails, but I will try to give more detail in the future (when I can :slight_smile: )

Thanks to all,
Jeff

This is the approach I use for my preloaders. It avoids the use of timeouts, or async/await.

const loader = new THREE.TextureLoader();

const allImageURLs = ["one.png", "two.jpg", "three.gif", "..."];
const allTextures = [];

let assetCount = 0;
let assetTotal = allImageURLs.length;

// Iterate through all image paths & load them
function loadAssets() {
	for (let i = 0; i < assetTotal; i++) {
		allTextures[i] = loader.load(allImageURLs[i], function(texture) {
			checkProgress();
		});
	}
}

// Gets called after each asset completes
function checkProgress() {
	assetCount ++;

	if (assetCount >= assetTotal) {
		loadingComplete();
	}
}

// Called when all assets have finished loading
function loadingComplete() {
	console.log("All assets are loaded!");
	console.log(allTextures);

	// ... Hide preloader bar
	// ... Start rendering scene with new assets
}

loadAssets();

This example is for textures only, but you could add other asset types to the assetTotal counter

2 Likes

Yes that is basically what I am doing just with set interval and using promise in the loadassets section and so far things are looking well.
Major difference on 3d objects, now going through others and updating and tweaking

As far as I understand you, you need a simple counter in your callback- function which you so increase with each finished loading and comparing with the expexted number of models to be loaded. If it matches you can proceed.

Yep, thanks, that’s basically how I did it, working like a charm

using timeouts is almost always a hack. when you load and await promises there is no way it can return without having loaded the asset, there was most likely something fundamentally wrong. like don mentioned, you probably forgot the await without which the function must return immediately. if you did have await, something else was off. you seem to be happy with the solution, so all is good - just saying, three code can be unwieldy on its own, adding timeout doesn’t really help when the app scales up.

the whole new awareness level :rofl: Let me throw one more method into the mix:

oh, you dont really have to use await, there is always Promise.all(....).then(yourFunction)

1 Like

I use promise all in my main loop, but when I tried to add it withe async, it just continued, see the way you have it, it does not wait till the first is done it lets the second go on as well, which is not what I needed, I wanted it to wait till first returns before next goes, not let them all go. I see no advantage of that as onload do the same, but I’m good ,now on to my next issues. I went from ver 90 to 116 and a buttload of stuff got broke, so now I am trying to fix those issues, most of the problems seem to be with shaders and such, so I’m sure I will be asking for help with those.

I do have a question, I know example/js folder was suppose to
Be deprecated but I still see file size changes in versions after 116. How far can I go before the es5 stuff stops working? It seems it went pass the date it was suppose to be removed.

Once I Get these things fixed, I want to try and upgrade as far as I can with es 5, project is way too fucking big to redo to es6 since this is mainly just a pet project I have been working on since 2014. Anyone with idea on what version I can safely go to?

Thanks all
Jeff

I’m glad your question was asked and answered.

I sometimes have a similar kind of issue with loading models that are linked to each other.
So far, the solution I have used is to make the loading of the second model a subroutine of the routine for loading the first model.

I would also be interested in the answer to your question about deprecation since that will likely entail a lot of changes to the way I do things, including the ability to test my programs locally before posting them on the web. But I assume that you will have to open a new discussion to get proper answers to that question.

It is my opinion that ES Modules (and examples/jsm) are better and more future-proof, and I do believe it’s worth the time to learn them. But there’s currently no announced plan or timeline for examples/js to be deprecated. The previous deprecation was removed.

I understand and maybe one day I wii break down and learn es6 but right now? I’ll probably stay the way I have it, this is a fun project and that sounds like work :crazy_face:

So am I correct that the js gltf and fbx loaders are still getting updates with each new version? To be honest, those 2 are the only reason I really moved on from v90.
V116 seems to handle most models I have but still does not seem to support transparency? Do you remember when you added that feature?

The /js and /jsm folders are both kept in sync, yes.

V116 seems to handle most models I have but still does not seem to support transparency?

Transparency has been supported for a very long time (long before r90), it sounds like something else might be going on in your code that may require a more detailed question.

Really? Wow should have checked, I had some models from sketchfab with glass that did not work for me but did in your app, but some did not work in either, will check at a later date…