Nuevo en js, quiero generar 5 '! con un intervalo de 1 segundo, y finalmente generar "fin". Pensé que el problema estaba relacionado con la asincronización. Lo he intentado muchas veces y muchos métodos como "esperar, asíncrono" y "promesa", pero aún así fallé.
class A { constructor() { this.cnt = 5; } real() { this.cnt--; console.log("!"); } getCnt() { return this.cnt; } } class B { constructor() { this.a = new A(); } fun() { if (this.a.getCnt() > 0) { this.a.real(); setTimeout(() => this.fun(), 1000); } } } class C { constructor() { this.b = new B(); } f() { this.b.fun(); console.log("end"); } } var c = new C(); cf();Saltándose la complejidad de las 3 clases involucradas, esto se resuelve elegantemente con funciones async . (Sin funciones asíncronas, la cascada de setTimeout s en un bucle se vuelve más difícil de administrar).
Por supuesto, esto puede incluirse en un trío de clases si es necesario.
// Turns `setTimeout` into a promise you can `await`. async function delay(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } // Calls a function `fun` `times` times, delaying for `delayTime` ms between each invocation. // Since this is an async function, it returns a promise that will resolve as soon as it's done, // which in turn can be awaited upon. async function repeatWithDelay(fun, times, delayTime) { for (let i = 0; i < times; i++) { await fun(i); await delay(delayTime); } } // Prints the number passed in (could just print an exclamation mark). function print(i) { console.log(`${i}!`); } async function main() { console.log("Go!"); await repeatWithDelay(print, 5, 500); console.log("Done!"); } // Assumes top-level `await` is not available in your environment. // If it is, this too can be replaced with a simple `await`. main().then(() => { console.log("Main done."); });esto se imprime
Go! 0! 1! 2! 3! 4! Done! Main done.En última instancia, debe hacer que su método sea fun para poder informar cuando finalice, ya que es un método asíncrono (llamadas a setTimeout ). La mejor manera de hacer esto es devolver una Promise que permite que las llamadas usen await en ella.
fun() { return new Promise(resolve => { const exec = () => { if (this.a.getCnt() > 0) { this.a.real(); setTimeout(exec.bind(this), 1000); } else{ resolve(); } } exec.apply(this); }) } Una vez que haya hecho eso, también marque la función f como async , lo que le permite llamar a la await dentro de ella:
async f() { await this.b.fun(); console.log("end"); }Y luego todo funciona como se esperaba:
class A { constructor() { this.cnt = 5; } real() { this.cnt--; console.log("!"); } getCnt() { return this.cnt; } } class B { constructor() { this.a = new A(); } fun() { return new Promise(resolve => { const exec = () => { if (this.a.getCnt() > 0) { this.a.real(); setTimeout(exec.bind(this), 1000); } else{ resolve(); } } exec.apply(this); }) } } class C { constructor() { this.b = new B(); } async f() { await this.b.fun(); console.log("end"); } } var c = new C(); cf();Traté de escribir una función genérica que emula la escritura, espero que esto te ayude a entender las funciones asíncronas/en espera
let fakeConsole = document.getElementById('console'); async function sleep(time) { await new Promise(r => setTimeout(r, time)); } function type(text) { fakeConsole.innerHTML += text; } async function emulateTyping(text, speed) { // split the text into an array of characters; const characters = text.split('').reverse(); if (characters.length > 0) { // display first character right away type(characters.pop()); while (characters.length > 0) { // wait <speed> millisections await sleep(speed); // type one character type(characters.pop()); } } } async function main() { // async function we wait for the end with "await" await emulateTyping("!!!!!", 500); // sync function type(' END'); }; main(); <pre id="console"></pre>