我在解决一个承诺时遇到了问题。
加载我的脚本有一个承诺,我希望解决何时包含3D文件导入的函数完成导入。
我面临的问题是如何使promise resolve()在模型加载后执行。
是否有一种方法来获取数据或任何类型的信号从浏览器当一个模型已经完成加载?
下面是承诺。我希望在generateContent()完成导入对象后执行res()。
const myGeneralAsyncPromise = new Promise((res, rej) => {
generateContent()
if(some condition) res()
// else rej()
})
myGeneralAsyncPromise.then(allIsReady, notReadyYet)
下面的代码调用一个在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);
下面是每个对象的实际导入。
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));
});
});
}
对于记录- generateContent()除了导入之外还有更多需要时间的过程-但导入是迄今为止最长的。
底线:在我的主要承诺,我错过了一个条件,将设置res()当模型已经完成加载。
你应该做出一个承诺,在load回调被调用时解决。换句话说,您应该承诺.load()
:
const promiseGLTFLoad = url =>
new Promise(resolve => new GLTFLoader_js_1.GLTFLoader().load(url, resolve));
使用这个函数,现在可以构建异步处理:
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;
}
现在到调用body
的地方——我想在generateContent
中:该函数应该收集承诺你得到,然后等待它们:
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??
}
最后,主驱动程序代码将这样做:
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);
也许你真的不需要那么多层。您可以检查generateContent
末尾是否有什么不正确的地方,并在那里引发错误(这转换为拒绝的承诺)。然后就变成了:
generateContent().then(allIsReady, failure);
注意这里没有"notReadyYet"。承诺不是解决问题就是拒绝。当它拒绝时,你应该认为它是失败的。没有"还没有"。情绪。