Search code examples
javascriptasync-awaitpromisethree.js

.then() not waiting for all promises to resolve


I'm Loading multiple gltf models using an async function and then using .then() I iterate through the results and add the models to my scene. It works perfectly fine until I remove one of the models from the source (the model I want to remove is larger than the rest), when I remove the model it seems like it's not waiting for all the promises to resolve before calling .then(). Below is the loader function, what am I doing wrong?

'source' is just an array of objects containing the model file paths

The error occurs in the .then(). If I remove one of the models (which is largest in size) from the 'source' array I get an error in the console: 'variant.components is not iterable'

async function modelLoader(source, loadingManager) {
    const gltfLoader = new GLTFLoader(loadingManager);
    const promises = [];
    for (let i = 0; i < source.length; i++) {
      promises.push(
        new Promise((resolve) => {
          const model = {}
          gltfLoader.load(source[i].file, (gltf) => {
            const children = [...gltf.scene.children];
            console.log(children);
              model.components = children;
            resolve(model);
          });
          if (source[i].type === 'baseModel' || (source[i].type === 'variant' && source[i].viewPoints.file !== 'none')) {
            gltfLoader.load(source[i].viewPoints.file, (gltf) => {
              const viewPoints = [...gltf.scene.children];
                model.viewPoints = viewPoints;
              resolve(model);
            });
          } else if (source[i].type === 'baseModel' || (source[i].type === 'variant' && source[i].viewPoints.file === 'none')) {
            model.viewPoints = 'none';
          } else if (source[i].type === 'land') {
            gltfLoader.load(source[i].buildingLine, (gltf) => {
              const buildingLine = [...gltf.scene.children]
              model.buildingLine = buildingLine
              resolve(model)
            })
          }
        })
      );
    }
    return await Promise.all(promises);
  }



const allModels = modelLoader(source, loadingManager)

allModels.then(result => {
    for (const variant of result) {
        if (variant.type === 'baseModel') {
            const house = new THREE.Group()
            for (const components of variant.components) {
                house.add(components)
            }       
        }                       
    }
})     

Solution

  • For anyone coming across the same issue, I found the solution, using await on each call of the gltfLoader fixed the issue.

      async function modelLoader(source, loadingManager) {
    const gltfLoader = new GLTFLoader(loadingManager);
    const models = [];
    
    for (let i = 0; i < source.length; i++) {
      const model = {
        name: source[i].name,
        type: source[i].type,
        isDefault: source[i].isDefault,
        section: source[i].section,
        isDetached: source[i].isDetached,
        isInterior: source[i].isInterior,
        price: source[i].price,
        image: source[i].image,
      };
    
      const gltf = await new Promise((resolve) => {
        gltfLoader.load(source[i].file, (gltf) => {
          resolve(gltf);
        });
      });
    
      const children = [...gltf.scene.children];
      model.components = children;
    
      if (
        source[i].type === 'baseModel' ||
        (source[i].type === 'variant' && source[i].viewPoints.file !== 'none')
      ) {
        const viewPointsGltf = await new Promise((resolve) => {
          gltfLoader.load(source[i].viewPoints.file, (gltf) => {
            resolve(gltf);
          });
        });
    
        const viewPoints = [...viewPointsGltf.scene.children];
        model.viewPoints = viewPoints;
      } else if (
        source[i].type === 'baseModel' ||
        (source[i].type === 'variant' && source[i].viewPoints.file === 'none')
      ) {
        model.viewPoints = 'none';
      } else if (source[i].type === 'land') {
        const buildingLineGltf = await new Promise((resolve) => {
          gltfLoader.load(source[i].buildingLine, (gltf) => {
            resolve(gltf);
          });
        });
    
        const buildingLine = [...buildingLineGltf.scene.children];
        model.buildingLine = buildingLine;
      }
    
      models.push(model);
    }
    
    return models;
    

    }