You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Three.js的loadModels函数返回含所有加载模型的Promise?

修改异步模型加载函数以返回包含所有模型的Promise

问题根源

原代码中GLTFLoader.load采用回调式异步逻辑,函数虽标记为async但未等待任何异步操作完成就直接结束,导致外部无法获取加载完成后的模型数组;同时全局models变量也存在作用域污染风险。

解决方案

将每个模型加载逻辑封装为Promise,通过Promise.all等待所有加载任务完成,最终返回包含所有模型的Promise。具体修改如下:

1. 封装Promise版GLTF加载工具函数

把回调式的loader.load转换为Promise,适配async/await语法:

function loadGLTF(loader, url) {
  return new Promise((resolve, reject) => {
    loader.load(url, resolve, undefined, reject);
  });
}

2. 重构loadModels函数

将每个模型的加载、处理逻辑拆分为独立异步任务,统一收集所有模型后返回:

async function loadModels(lights, roomWidth, roomHeight) {
  const loader = new GLTFLoader(loadingManager);

  // 加载并处理灯光模型(含多个克隆体)
  const loadLight = async () => {
    const gltf = await loadGLTF(loader, './models/scifi_light_11.glb');
    gltf.scene.scale.set(0.02, 0.02, 0.02);
    gltf.scene.rotateZ(-0.7 * Math.PI);
    gltf.scene.receiveShadow = true;
    gltf.scene.castShadow = true;

    const lightModels = [];
    // 初始模型
    gltf.scene.position.set(-(roomWidth / 2) + 0.32, roomHeight - 0.4, 0);
    scene.add(gltf.scene);
    lightModels.push(gltf.scene);
    // 克隆模型1
    const l1 = gltf.scene.clone(true);
    l1.position.set(-roomWidth / 2 + 0.32, roomHeight - 0.4, -roomWidth);
    scene.add(l1);
    lightModels.push(l1);
    // 克隆模型2
    const l2 = gltf.scene.clone(true);
    l2.position.set(roomWidth / 2 + 0.32, roomHeight - 0.4, -roomWidth);
    scene.add(l2);
    lightModels.push(l2);
    // 克隆模型3
    const l3 = gltf.scene.clone(true);
    l3.position.set(roomWidth / 2 + 0.32, roomHeight - 0.4, -2 * roomWidth);
    scene.add(l3);
    lightModels.push(l3);
    // 克隆模型4
    const l4 = gltf.scene.clone(true);
    l4.position.set(-roomWidth / 2 + 0.32, roomHeight - 0.4, -2 * roomWidth);
    scene.add(l4);
    lightModels.push(l4);

    return lightModels;
  };

  // 加载并处理终端模型
  const loadTerminal = async () => {
    const loader1 = new GLTFLoader(loadingManager);
    const gltf = await loadGLTF(loader1, './models/terminal/scene.gltf');
    let model = gltf.scene;
    model.traverse(node => {
      if (node.isMesh) node.castShadow = true;
    });
    model.scale.set(8, 8, 8);
    model.rotateY(0.6);
    const randomX = Math.random() * (roomWidth / 4 - (-roomWidth / 4)) + (-roomWidth / 4);
    const randomZ = Math.random() * (roomWidth / 4 - (-roomWidth / 4)) + (-roomWidth / 4);
    model.position.set(randomX, 0, randomZ);
    scene.add(model);
    return [model];
  };

  // 加载并处理胶囊模型
  const loadCapsule = async () => {
    const loader2 = new GLTFLoader(loadingManager);
    const gltf = await loadGLTF(loader2, './models/capsule/scene.gltf');
    let model = gltf.scene;
    model.traverse(node => {
      if (node.isMesh) node.castShadow = true;
    });
    model.scale.set(0.01, 0.01, 0.01);
    const randomX = Math.random() * (roomWidth / 4 - (-roomWidth / 4)) + (-roomWidth / 4);
    const randomZ = Math.random() * (roomWidth / 4 - (-roomWidth / 4)) + (-roomWidth / 4);
    model.position.set(randomX, 0, -roomWidth + randomZ);
    model.rotateY(-0.6);
    lights[1].target = model;
    scene.add(model);
    return [model];
  };

  // 加载并处理立方体模型
  const loadCube = async () => {
    const loader3 = new GLTFLoader(loadingManager);
    const gltf = await loadGLTF(loader3, './models/cube/scene.gltf');
    let model = gltf.scene;
    model.traverse(node => {
      if (node.isMesh) node.castShadow = true;
    });
    model.scale.set(8, 8, 8);
    const randomX = Math.random() * (roomWidth / 4 - (-roomWidth / 4)) + (-roomWidth / 4);
    const randomZ = Math.random() * (roomWidth / 4 - (-roomWidth / 4)) + (-roomWidth / 4);
    model.position.set(roomWidth + randomX, 0.2, -roomWidth + randomZ);
    model.rotateY(0.6);
    lights[2].target = model;
    scene.add(model);
    return [model];
  };

  // 加载并处理 barrel 模型
  const loadBarrel = async () => {
    const loader4 = new GLTFLoader(loadingManager);
    const gltf = await loadGLTF(loader4, './models/barrel/scene.gltf');
    let model = gltf.scene;
    model.traverse(node => {
      if (node.isMesh) node.castShadow = true;
    });
    model.scale.set(0.04, 0.04, 0.04);
    const randomX = Math.random() * (roomWidth / 4 - (-roomWidth / 4)) + (-roomWidth / 4);
    const randomZ = Math.random() * (roomWidth / 4 - (-roomWidth / 4)) + (-roomWidth / 4);
    model.position.set(roomWidth + randomX, 0, -2 * roomWidth + randomZ);
    model.rotateY(-0.6);
    lights[3].target = model;
    scene.add(model);
    return [model];
  };

  // 加载并处理反应堆模型
  const loadReactor = async () => {
    const loader5 = new GLTFLoader(loadingManager);
    const gltf = await loadGLTF(loader5, './models/reactor/scene.gltf');
    let model = gltf.scene;
    model.traverse(node => {
      if (node.isMesh) node.castShadow = true;
    });
    model.scale.set(0.6, 0.6, 0.6);
    const randomX = Math.random() * (roomWidth / 4 - (-roomWidth / 4)) + (-roomWidth / 4);
    const randomZ = Math.random() * (roomWidth / 4 - (-roomWidth / 4)) + (-roomWidth / 4);
    model.position.set(randomX, 1, -2 * roomWidth + randomZ);
    model.rotateY(-0.6);
    lights[4].target = model;
    scene.add(model);
    return [model];
  };

  // 等待所有加载任务完成,合并所有模型数组
  const allModelGroups = await Promise.all([
    loadLight(),
    loadTerminal(),
    loadCapsule(),
    loadCube(),
    loadBarrel(),
    loadReactor()
  ]);

  // 扁平化数组,返回一维模型列表
  return allModelGroups.flat();
}

3. 使用方式

调用loadModels时,可通过await或.then获取加载完成的所有模型:

// 方式1:在async函数内使用await
async function initScene() {
  try {
    const allModels = await loadModels(lights, roomWidth, roomHeight);
    console.log('所有模型加载完成', allModels);
    // 后续场景初始化逻辑
  } catch (err) {
    console.error('模型加载失败', err);
  }
}

// 方式2:使用Promise链式调用
loadModels(lights, roomWidth, roomHeight)
  .then(allModels => {
    console.log('所有模型加载完成', allModels);
    // 后续场景初始化逻辑
  })
  .catch(err => {
    console.error('模型加载失败', err);
  });

关键说明

  • 每个模型加载任务拆分为独立异步函数,便于维护和逻辑分离
  • loadGLTF工具函数统一处理回调转Promise的逻辑,避免重复代码
  • Promise.all确保所有模型加载完成后才返回结果,解决异步时序问题
  • 最终返回扁平化的一维数组,包含所有原始模型和克隆模型

内容的提问来源于stack exchange,提问作者FlorNeufkens

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 02:02:33