Im having a problem resolving a promise.
on load my script has a promise that i wish to resolve when a function that contains 3D file imports finishes importing.
the problem im facing is how to make the promises resolve() execute when a model has loaded.
is there a way to get data or any sort of signal from the browser when a model has finished loading?
the following is the promise. i wish to execute res() when generateContent() has finished importing objects.
const myGeneralAsyncPromise = new Promise((res, rej) => {
generateContent()
if(some condition) res()
// else rej()
})
myGeneralAsyncPromise.then(allIsReady, notReadyYet)
the following envokes a class that creates an object within generateContent().
var arrow3 = body(scene, world, 'static', 'arrow', { hx: 0.2, hy: 0.2, hz: 0.2 }, { x: 34.5, y: 3.35, z: 6 }, { x: 0, y:11, z: 0});
bodys.push(arrow3);
var phone = body(scene, world, 'static', 'phone', { hx: 1.3, hy: 1.3, hz: 1.3 }, { x: 35.35, y:1.8, z: 6.5 }, { x: 0, y:0, z: 0});
bodys.push(phone);
var pencil = body(scene, world, 'static', 'pencil', { hx: 2, hy: 2, hz: 2 }, { x: 35.5, y:1.8, z: 14 }, { x: 0, y:11, z: 0});
bodys.push(pencil);
the following is the actual import of each object.
function body(scene, world, bodyType, colliderType, dimension, translation, rotation) {
new GLTFLoader_js_1.GLTFLoader().load(`src/models/${colliderType}.glb`, function (gltf) {
var model = gltf.scene;
collider = gltf.scene
model.scale.x = dimension.hx
model.scale.y = dimension.hy
model.scale.z = dimension.hz
model.traverse(function (object) {
if (object.isMesh)
object.castShadow = true;
});
model.position.x = translation.x
model.position.y = translation.y
model.position.z = translation.z
model.rotation.x = rotation.x
model.rotation.y = rotation.y
model.rotation.z = rotation.z
scene.add(model);
var gltfAnimations = gltf.animations;
var mixer = new THREE.AnimationMixer(model);
var animationsMap = new Map();
gltfAnimations.filter(function (a) { return a.name != 'TPose'; }).forEach(function (a) {
animationsMap.set(a.name, mixer.clipAction(a));
});
});
}
for the record - generateContent() has more processes that take time besides the import - but the import is by far the longest.
bottom line: in my main promise im missing a condition that will set res() when the models has finished loading.
CodePudding user response:
You should make a promise that resolves when the load callback is called. In other words, you should promisify .load()
:
const promiseGLTFLoad = url =>
new Promise(resolve => new GLTFLoader_js_1.GLTFLoader().load(url, resolve));
With this function you can now build the asynchronous processing:
async function body(scene, world, bodyType, colliderType, dimension, translation, rotation) {
const gltf = await promiseGLTFLoad(`src/models/${colliderType}.glb`);
var model = gltf.scene;
collider = gltf.scene
model.scale.x = dimension.hx
/* ... etc ... */
scene.add(model);
var gltfAnimations = gltf.animations;
var mixer = new THREE.AnimationMixer(model);
var animationsMap = new Map();
gltfAnimations.filter(a => a.name != 'TPose')
.forEach(a => animationsMap.set(a.name, mixer.clipAction(a)));
// Need to return the result!!
return animationsMap;
}
Now to where you call body
--- I suppose in generateContent
: that function should collect the promises you get and then await them:
async function generateContent() {
// ...
var arrow3Promise = body(scene, world, 'static', 'arrow', { hx: 0.2, hy: 0.2, hz: 0.2 }, { x: 34.5, y: 3.35, z: 6 }, { x: 0, y:11, z: 0});
var phonePromise = body(scene, world, 'static', 'phone', { hx: 1.3, hy: 1.3, hz: 1.3 }, { x: 35.35, y:1.8, z: 6.5 }, { x: 0, y:0, z: 0});
var pencilPromise = body(scene, world, 'static', 'pencil', { hx: 2, hy: 2, hz: 2 }, { x: 35.5, y:1.8, z: 14 }, { x: 0, y:11, z: 0});
// Wait for all promises to resolve
var bodys = await Promise.all(arrow3Promise, phonePromise, pencilPromise);
// ... etc
return bodys; // Maybe the caller needs them??
}
Finally, the main driver code would do this:
async function main() {
const bodys = await generateContent();
if (something is not right) throw new Error("my error");
// ...
return bodys; // Maybe the caller needs them??
}
main().then(allIsReady, failure);
Maybe you don't really need that many layers. You could check if something is not right at the end of generateContent
and raise an error there (which translates to a rejected promise). And then it just becomes:
generateContent().then(allIsReady, failure);
Note that there is no "notReadyYet". A promise either resolves or rejects. When it rejects, you should consider it a failure. There is no "not yet" sentiment here.