JS/TS中await调用返回Promise的GLTF解析函数未生效问题排查
问题排查结论
你的代码无法正常返回结果是4个核心问题导致的:
- 循环内部直接写
return:遍历toAdd数组时只要碰到第一个类型为part的项,就会直接退出整个函数,后续所有项都不会处理;如果数组第一个元素不是part类型,循环走完后函数没有任何返回值,await拿到的是undefined,自然等不到异步结果。 - 未处理GLTFLoader的错误分支:
loader.parse方法第四个参数是错误回调,你没有传入,解析失败时既不会抛出错误也不会让Promise进入reject状态,会直接静默卡住。 - 缺少类型与空值校验:你默认
gltf.scene.children[0]一定是带geometry的Mesh对象,如果gltf结构存在嵌套、第一个子元素是Group分组而非Mesh,读取geometry属性时会直接抛错,且该错误未被Promise捕获,会导致Promise永远无法决议。 - 未做批量异步等待:原逻辑只返回单个模型解析的Promise,没有等待所有part类型的模型全部解析完成,多模型场景下逻辑不完整。
修复后完整实现
parseGltfBlobs方法可直接替换原有代码:
public async parseGltfBlobs(toAdd: asmTreeNodeScene[]): Promise<void> { const loader = new GLTFLoader(); // 收集所有待解析模型的异步任务 const parseTasks: Promise<void>[] = []; for (let i = 0; i < toAdd.length; i++) { const componentId: number = toAdd[i].componentId; const isPart: boolean = toAdd[i].type == "part"; if (isPart) { const surfaceMeshKey: string = `${componentId}.${this.asmStateServ.decimation}`; // 提前校验缓存是否存在,避免读取null报错 const meshCache = this.assemblyFetchServ.surfaceMeshesGltf.get(surfaceMeshKey); if (!meshCache?.gltfBytes) { console.warn(`未找到componentId为${componentId}的gltf缓存数据,跳过解析`); continue; } const gltfBytes = <ArrayBuffer>meshCache.gltfBytes; // 为每个模型创建独立解析任务,加入任务列表,不在循环内直接return const parseTask = new Promise<void>((resolve, reject) => { loader.parse( gltfBytes, "", (gltf) => { try { // 递归查找场景中的Mesh,兼容Group嵌套结构 const findMesh = (obj: THREE.Object3D): THREE.Mesh | null => { if ((obj as THREE.Mesh).isMesh) return obj as THREE.Mesh; for (const child of obj.children) { const res = findMesh(child); if (res) return res; } return null; }; const mesh = findMesh(gltf.scene); if (!mesh) { reject(new Error(`componentId为${componentId}的gltf中未找到有效Mesh对象`)); return; } if (!mesh.geometry.attributes.position || !mesh.geometry.index) { reject(new Error(`componentId为${componentId}的Mesh缺少顶点或索引数据`)); return; } const vertices = mesh.geometry.attributes.position.array; const faces = mesh.geometry.index.array; const surfaceMesh = { "component_id": componentId, "vertices": vertices, "faces": faces, }; this.assemblyFetchServ.surfaceMeshes.set(surfaceMeshKey, surfaceMesh); console.log(`已存储componentId为${componentId}的网格数据`); resolve(); } catch (err) { reject(err); } }, // 传入解析错误回调 (err) => { reject(new Error(`解析componentId为${componentId}的gltf失败: ${err?.message || err}`)); } ); }); parseTasks.push(parseTask); } } // 等待所有解析任务完成,任意任务失败会抛出对应错误 await Promise.all(parseTasks); }
调用部分补充错误捕获即可,原有逻辑无需大改:
this.requestMissingResources(toAdd, this.isGLTF).subscribe( () => {}, (err) => { console.log(err); }, async () => { if(this.isGLTF) { console.log("开始解析gltf数据"); try { await this.parseGltfBlobs(toAdd); console.log("所有gltf数据解析完成"); // 此处写解析完成后需要执行的后续业务逻辑 } catch (parseErr) { console.error("gltf解析流程出错:", parseErr); } } } )
内容的提问来源于stack exchange,提问作者GeekAndNerd223
相关产品推荐
相关产品推荐

