Search code examples
javascripttypescriptpromisethree.jsgltf

Using await in javascript after returning a promise


I have a function that needs to be executed. I used the GLTF parser to retrieve the vertices and faces. However it does not execute in the right time. This is the function that I currently have.

public parseGltfBlobs(toAdd: asmTreeNodeScene[]) {
        const loader = new GLTFLoader();

        for (let i = 0; i < toAdd.length; i++) {
            let componentId: number = toAdd[i].componentId;

            let isPart: boolean = toAdd[i].type == "part";
            
            // Handle surface mesh requests for parts for server endpoint in json format
            if (isPart) {       
                let surfaceMeshKey: string = componentId.toString() + "." + this.asmStateServ.decimation.toString();

                // Grab the byte array
                let gltfBytes = <ArrayBuffer>this.assemblyFetchServ.surfaceMeshesGltf.get(surfaceMeshKey)['gltfBytes'];
            
                return new Promise((resolve, reject) => {
                    
                    loader.parse(gltfBytes, "", gltf => {
                    let mesh;
                    let vertices;
                    let faces;
                    
                    mesh = <THREE.Mesh>gltf.scene.children[0];
                    vertices = mesh.geometry.attributes.position.array;
                    faces = mesh.geometry.index.array;

                    let surfaceMesh: Object = {
                        "component_id": componentId,
                        "vertices": vertices,
                        "faces": faces,
                    }
                    resolve(this.assemblyFetchServ.surfaceMeshes.set(surfaceMeshKey, surfaceMesh));
                    console.log("Stored data  in surfaceMeshes map")
                    // Emit finished event
                }
               )
            })}
        }
    }

The function is being called in the following way.

this.requestMissingResources(toAdd, this.isGLTF).subscribe(
            () => {
            },
            (err) => {
                console.log(err);
            },
            async () => {
                if(this.isGLTF) {
                    console.log("Parsing gltf blobs");
                    await this.parseGltfBlobs(toAdd);
                    console.log("End of parsing gltf blobs")
                }

However, I still do not receive the output promise. I was wondering why that is and what I am doing wrong out here? It would mean a lot if the correct code is given to me as that would help me out a lot as I am very new to this.


Solution

  • Moving answers from comments.

    1. Looks like your promise doesn't have/call the resolve callback to even know it is finished.

    When creating a promise define callbacks to mark it as completed successfully or failed. You use resolve and reject callbacks for it as so:

    new Promise((resolve, reject) => { ... do something ... resolve(data); })
    
    1. I don't see anything receiving the result of the promise anyway, nor returning any results from the promise. If you're not planning on returning any info from promise at least call resolve with a boolean in it to mark it as completed for you to know if you can proceed further or not.

    The resolve(data) or reject(data) will help you correctly handle the promise. Try/catch works on catching these outputs.

    try {
      // if promise resolved successfully you will get data in the data variable
      const data = await function_returning_a_promise();
    }
    catch (error) {
      // if promise rejected you will catch an error here
      console.error(error);
    }
    
    1. use try/catch to handle promises with await as above.

    2. Is there anything asynchronous that you require a promise to parse it? Is this.assemblyFetchServ.surfaceMeshes.set asynchronous? If so you probably should wait for it to complete as well with another await. And if not you probably don't even need a promise at all.

    So what I mean is:

    const result = await this.assemblyFetchServ.surfaceMeshes.set(surfaceMeshKey, surfaceMesh);
    

    If that's an asynchronous function you should wait for it to complete first. And if it is not you probably shouldn't even use promises in the first place.

    I'd recommend reading through https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise carefully. Back in time it helped me a lot to understand promises myself.