簡體   English   中英

關於使用 Promise 和 three.js 導入模型的異步問題

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM