Aquí está mi código, estoy tratando de hacer que loadCone() sincrónico con await/async pero no funciona.
import * as THREE from "three"; import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; import conePath from "../../static/cone.glb"; import coneBaked from "../../static/coneBake.png"; import "regenerator-runtime/runtime"; export default class Cone { constructor() { this.cone; const textureLoader = new THREE.TextureLoader(); const bakedTexture = textureLoader.load(coneBaked); const bakedMaterial = new THREE.MeshBasicMaterial({ map: bakedTexture, }); this.loadCone(); } async loadCone() { // GLTF loader const gltfLoader = new GLTFLoader(); const cone = await gltfLoader.load( conePath, (gltf) => { console.log("success"); console.log(gltf.scene); this.cone = gltf.scene; }, (progress) => { // console.log("progress"); // console.log(progress); }, (error) => { console.log("error"); console.log(error); } ); } getCone() { return this.cone; } }En otro archivo tengo esto:
const cone = new Cone(); this.scene.add(cone.getCone()); Sin embargo, debido a que getCone() es síncrono, se ejecuta antes de que loadCone() cargar el cono, por lo que obtengo una respuesta undefined en lugar del cono.
¿Cómo hago para que mi función asynch loadCone() sea síncrona? Probé *.loadAsync()` pero no cambió nada.
Gracias por adelantado. No recibo más errores que el hecho de que dice "indefinido no es una instancia de TRES.Objeto.3d", que esperaba que dijera.
No puedo entender muy bien lo que estás haciendo.
Yo uso esto con éxito:
// Load a glTF resource async loadGltf(url) { // console.log('===== start loadGltf async') let urlString = url.toString() // load doesn't like the url structure; it requires a string and then builds it up again let gltf = await gltfLoader.loadAsync(urlString) // console.log('========== end loadGltf') return gltf } Desde el resultado, acceda a result.scene
No sé three.js, pero new necesita devolver sincrónicamente un objeto inicializado, por lo que no puede ser (o invocar otra cosa que sea) asíncrono.
// ... constructor() { this.cone; const textureLoader = new THREE.TextureLoader(); const bakedTexture = textureLoader.load(coneBaked); const bakedMaterial = new THREE.MeshBasicMaterial({ map: bakedTexture, }); // don't call an async method here // this.loadCone(); } //...Del lado de la persona que llama...
import Cone from 'path to js that defines the class' // inside an async function async function doConeStuff() { const cone = new Cone(); await cone.loadCone(); this.scene.add(cone.getCone()); } // or, at the top level const cone = new Cone(); cone.loadCone().then(() => { this.scene.add(cone.getCone()) }); Al notar que loadCone está mezclando promesas y devoluciones de llamada, podemos prometer la versión que está usando o tomar la sugerencia de @ Leon.Z sobre la versión de devolución de promesa. Si ese funciona (nuevamente, no sé three.js), entonces la clase de cono se puede simplificar así...
export default class Cone { constructor() { const textureLoader = new THREE.TextureLoader(); const bakedTexture = textureLoader.load(coneBaked); const bakedMaterial = new THREE.MeshBasicMaterial({ map: bakedTexture, }); this.cone = null; } async loadCone() { // GLTF loader if (this.cone) Promise.resolve(this.cone); const giltf = await gltfLoader.loadAsync( 'model.gltf' ), this.cone = gilt.scene; return this.cone; } getCone() { return this.cone; } }Finalmente, si por alguna razón, @Leon.Z es incorrecto sobre el método de promesa, así es como le prometerías al cargador...
async loadCone() { const gltfLoader = new GLTFLoader(); return new Promise((resolve, reject) => { gltfLoader.load( conePath, gltf => resolve(gilt.scene), error => reject(error) ); }); }