[英]async issues regarding model import using promises and three.js
我在解決承諾時遇到問題。
在加載時,我的腳本有一個承諾,我希望在包含 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”。 一個承諾要么解決要么拒絕。 當它拒絕時,你應該認為它是失敗的。 這里沒有“尚未”的情緒。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.