Espere a que una función termine en JavaScript
-
Sync
yAsync
en JavaScript -
Use
callback
para esperar a que una función termine en JavaScript -
Usa
promises
para esperar a que una función termine en JavaScript -
Use
async/await
para esperar a que una función termine antes de continuar la ejecución
Este tutorial introducirá JavaScript Callbacks
, Promises
, y Async/await
y le mostrará cómo esperar a que una función de asíncrono termine antes de continuar la ejecución.
Para entender lo que son Promises
y Async/await
, primero necesitamos entender lo que las funciones Sync
y Async
están en JavaScript.
Sync
y Async
en JavaScript
La programación sincrónica ejecuta un comando a la vez. Cuando llamamos a una función que realiza una acción de larga duración, detendrá el programa hasta que termine.
JavaScript es tradicionalmente de un solo subproceso, incluso con multi-núcleos. Podemos hacer que ejecute tareas sólo en un único hilo llamado hilo principal.
Este comportamiento sincrónico es un factor limitante en los multi-hilos, pero ayuda al usuario a escribir códigos sin preocuparse por problemas de concurrencia.
Mientras que en la programación asíncrona, la acción de larga duración se ejecutará en otro hilo que no sea el principal, por lo que la ejecución principal no se bloquea. Cuando esa función de larga duración termina, el programa principal es informado y obtiene acceso a los resultados.
La mayoría de las primitivas de E/S en JavaScript no se bloquean. Las solicitudes de red, las operaciones del sistema de archivos son todas operaciones no bloqueantes. Estar bloqueado es la excepción en JavaScript.
Ya que JavaScript se basa en técnicas de programación asíncrona, hay múltiples enfoques como callbacks
, promises
y async/wait
que permiten poner en secuencia las ejecuciones de las funciones. De modo que un bloque de código o una función no se ejecutará antes de que termine otra función específica.
La figura anterior muestra la clara variación entre la ejecución asíncrona y síncrona de dos funciones.
Use callback
para esperar a que una función termine en JavaScript
Si tenemos declaraciones sincrónicas, entonces ejecutar esas declaraciones una tras otra es sencillo.
function one() {
console.log('I am function One');
}
function Two() {
console.log('I am function Two');
}
one();
Two();
Resultado:
I am function One
I am function Two
Supongamos que queremos ejecutar dos funciones, functionOne()
y functionTwo()
, de tal manera que functionOne()
debe ser ejecutada después de ejecutar algunas declaraciones asincrónicas dentro de functionTwo()
.
function functionOne(_callback) {
// do some asynchronus work
_callback();
}
function functionTwo() {
// do some asynchronus work
functionOne(() => {
console.log('I am a callback');
});
}
functionTwo();
Al ejecutar el código anterior, lo último que se imprime en la consola es I am a callback
. El famoso ejemplo de callback
es la función setTimeout
con una función de manejo que se ejecuta después del timing out
.
function testCallBack() {
console.log('log before use setTimeout function');
setTimeout(() => {
console.log('inside timeout');
}, 5000);
console.log('log after use setTimeout function');
}
testCallBack();
Resultado:
log before use setTimeout function
log after use setTimeout function
inside timeout
Usa promises
para esperar a que una función termine en JavaScript
Una promises
es un objeto que representa el eventual cumplimiento o fracaso de una operación asíncrona. Adjuntamos la llamada de cumplimiento a la promises
con una o más declaraciones de then
, y cuando se puede llamar a la llamada del manejador de errores en la catch
.
doFirstThing()
.then(result => doSecondThing(result))
.then(newResult => doThirdThing(newResult))
.then(finalResult => {
console.log('The final result thing' + finalResult);
})
.catch(failureCallbackfunction);
}
Encadenar las declaraciones de then
y catch
como en el ejemplo anterior es una de las ventajas de las promesas. Prometemos doSecondThing(result)
una vez que la doFirstThing()
se cumpla. Los argumentos del then
son opcionales, pero obligatorios si tienes que devolver un resultado.
En caso de que haya un error, el navegador buscará al final de la cadena el catch
y lo ejecutará. Es muy similar a la famosa try-catch
.
El siguiente ejemplo nos ayudará a entender las cadenas de promises
y nos mostrará cómo podemos esperar a que una función con comportamiento asíncrono termine su ejecución antes de poder continuar con ella.
var resolvedFlag = true;
let mypromise = function functionOne(testInput) {
console.log('Entered function');
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('Inside the promise');
if (resolvedFlag == true) {
resolve('Resolved');
} else {
reject('Rejected')
}
}, 2000);
});
};
mypromise()
.then((res) => {console.log(`The function recieved with value ${res}`)})
.catch((error) => {
console.log(`Handling error as we received ${error}`);
});
Resultado:
Entered function
Inside the promise
The function received with value Resolved
Crear una promesa puede ser tan fácil como devolver una nueva Promise()
. El constructor Promise()
recibe una función como argumento, que debe tener dos parámetros - resolve
y reject
.
En caso de que nuestro evento se cumpla, y necesitemos devolver el resultado, usamos la función resolve()
cuando tenemos éxito en lo que estábamos haciendo. Pero si ocurre un error y necesita ser manejado, usamos reject()
para enviar el error al catch
.
Ponemos la bandera resolvedFlag = true
para simular el manejo del error en el catch
. Si resolvedFlag
se establece como false
, se llama a la función reject()
y el error se maneja en el bloque catch
.
Resultado:
Entered function
Inside the promise
Handling error as we received Rejected
Use async/await
para esperar a que una función termine antes de continuar la ejecución
Otra forma de esperar a que una función se ejecute antes de continuar la ejecución en el entorno asíncrono en JavaScript es usar async/await
.
La función async
es la función que es declarada por la palabra clave async
, mientras que sólo la palabra clave await
se permite dentro de la función async
y se usa para suspender el progreso dentro de la función async
hasta que la operación asíncrona basada en la promesa se cumpla o se rechace.
Las palabras clave async/await
permiten un comportamiento asincrónico basado en la promesa en un estilo más limpio.
Entendamos cómo funciona async/await
. La función que estamos esperando debería devolver una instancia de la clase Promise
para esperar que se ejecute usando la palabra clave await
antes de llamarla. Como se mencionó anteriormente, la función que contiene la declaración await
debe ser declarada con la declaración async
.
El siguiente ejemplo muestra cómo esperar a que esa función basada en la promesa termine antes de continuar la ejecución.
function testAsync() {
return new Promise((resolve, reject) => {
// here our function should be implemented
setTimeout(() => {
console.log('Hello from inside the testAsync function');
resolve();
;
}, 5000);
});
}
async function callerFun() {
console.log('Caller');
await testAsync();
console.log('After waiting');
}
callerFun();
Resultado:
Caller
Hello from inside the testAsync function
After waiting