Hoy aprenderemos en este post como manejar de forma fácil qué es ASYNC y AWAIT y como implementar esta funcionalidad que nos da JavaScript ES6 para solventar el problema de los callback hell
.
Lo primero que he de decir es que son una mejora a los llamados Generators
en JavaScript.
¿Qué son las callback hell?
Las callback hell en principio no son fáciles de explicar con palabras mejor verlo en código pero si tuviera que decir qué son las callback hell diría que se producen cuando intentamos hacer un código Asíncrono en JavaScript y usamos «callback» para que de forma asíncrona se ejecute una función cuando termine de ejecutarse parte del código de una función y si encadenamos muchas operaciones asíncronas seguidas se producirá este infierno de llamadas, pero mejor verlo en imagen para tener una idea más clara.
Bien, como podemos observar esto es un infierno, el poder manejar el flujo de nuestra ejecución y hace que el código sea ilegible por nosotros, por no decir lo complicado que es depurar este código.
La solución que nos da el comité ECMAScript es un wrapper o envoltorio que va un paso más allá para manejar las llamadas asíncronas mediante los iterables como son los Generators
en JavaScript y que estos Generators siempre tenían que ir acompañado de bibliotecas como "co"
para manejar el flujo de llamadas asíncronas dentro de una función.
¿Qué son los Generators en JavaScript?
Pues como dije anteriormente es una manera de llamar a varias funciones de forma asíncronas iterando de forma que cuando termine la ejecución de la primera función se ejecute la segunda función y así sucesivamente y todo esto desde una única función la cual se marcaba con el signo de asterisco "*"
, veamos un ejemplo:
/* * Create function with asterisk this function it's a generators * * This function return an object <Iterator> */ function* runGenerators(){ // Call functions with yield before of function call yield first(); // Step one from next() method yield second(); // Step two from next() method } // Asynchronous call first from iterator object with next() method. function first(){ console.log("First call.."); } // Asynchronous call first from iterator object with next() method. function second (){ console.log("Second call.."); } // Return Iterator into myIterator let myIterator = runGenerators(); // Sleep myIterator.next(); myIterator.next(); // Output script: // First call.. // Second call.. //
Como se puede observar primero ejecuta una primera iteración cuando se ejecuta el método next() del iterador y hasta que esta no termine y se vuelva a llamar de nuevo al método next() del iterador no se ejecuta la siguiente sentencia o paso que este caso es la función second().
Esto es solo un ejemplo sobre los Generators muy básico en otro post hablaremos con todo detalle sobre cómo usar de forma fácil los Generators en JavaScript ES6.
Una vez visto los Generators podemos hacernos una idea de porque se implemento en ES6 la nueva funcionalidad ASYNC/AWAIT y cómo esta va a solucionar el tener que usar librerías de terceros para el manejo de la programación funcional asíncrona en JavaScript. Bien ahora veamos
¿Por qué usar siempre ASYNC/AWAIT?
Simplemente porque esta nueva funcionalidad es y será un standard en JavaScript ES6 el cual es una mejora muy importante en el manejo de las llamadas asíncronas y el flujo y control de estas.
Diferencias entre Generators
y ASYNC/AWAIT
- async/await usa
await
en vez deyield
- await solo funciona con Promesas
- En lugar de
function*
, usa la palabra claveasync function
.
Así que async/await
es esencialmente un subconjunto o mejora de generators y tiene un nuevo azúcar sintáctico.
La palabra clave async
le dice al compilador de JavaScript que trate la función de manera diferente. El compilador se detiene cada vez que llega a la palabra clave await
dentro de esa función. Asume que la expresión después de await
devuelve una promesa y espera hasta que la promesa se resuelva o se rechace antes de seguir adelante.
Bueno después de tanta explicación será mejor ver cómo se implementa ASYNC y AWAIT en un ejemplo básico.
// Create first function function getUserById(userId){ // Return a Promise return new Promise(resolve => { setTimeout(() => { resolve({ name: "Francisco", job: "developer"}); // Send second call.. }, 1000); }, reject => { // Reject value.. }); } // Create second function // This function it depends on the function first for ejecution function getUserProfile(userProfile){ let {name, job} = userProfile; // to receive of first Promise // Return a Promise return new Promise( (resolve, reject) => { setTimeout(() => { if ( name === "Francisco") { resolve(`User ${name} is correct and he works as ${job} `); } else { reject("User unknown.."); } }, 1000); }); } // Use of ASYNC/AWAIT very easy async function getProfile(userId){ let myUser = await getUserById(); let myProfile = await getUserProfile(myUser); // console.log(myProfile); } // Ejecute asynchronous call getProfile("100"); // Output console // User Francisco is correct and he works as developer //
Bien cómo podemos observar el manejo de las llamadas asíncronas o callback se hace muy fácil de crear y sobre todo de testear en nuestro código por lo que es recomendable el uso de la nueva funcionalidad ASYNC/AWAIT que JavaScript ES6 nos proporciona.
// Use of ASYNC/AWAIT very easy async function getProfile(userId){ let myUser = await getUserById(); let myProfile = await getUserProfile(myUser); // console.log(myProfile); } // \ 0 / - \ 0 / - \ 0 / //
Además de esta forma de iteración sobre funciones, ES2018 nos trae for-await-of
para iterar en un bucle for y poder hacer llamadas a funciones que retornan Promises de forma asíncrona. Veamos un pequeño ejemplo:
// Create all Promises const promises = [ new Promise(resolve => resolve("Sleep one..")), new Promise(resolve => resolve("Sleep two..")), new Promise(resolve => resolve("Sleep three..")) ]; // Use of ASYNC/AWAIT async function testPromises() { for await (const promise of promises) { console.log(promise); } } // Run testPromises(); // Output // Sleep one.. // Sleep two.. // Sleep three.. //
Una vez más vemos cómo esta funcionalidad de ES2018 nos facilita enormemente el manejo de llamadas callback de forma asíncrona dentro de un bucle.
Conclusión:
Hemos visto como ES6 trae nuevos azúcar sintáctico como es el manejo de callback de forma asíncrona mediante ASYNC/AWAIT
. No debemos de desaprovechar esta mejora que JavaScript proporciona una abstracción de mayor nivel que los generators para resolver específicamente el problema de los callback.
En cuanto a la iteración en un bucle for-await-of
es una característica completamente nueva del 2018 para ayudar a realizar dentro de un bucle una serie de llamadas (callback) a funciones asíncronas y obtener el resultado de cada función asíncrona de forma normal.
- Aprende de forma fácil qué es ASYNC y AWAIT en JavaScript ES6 - abril 14, 2019
- Manejar o atrapar las excepciones en java de forma sencilla - abril 4, 2019
- Todo sobre Destructuring Assignment en JavaScript ES6 - marzo 29, 2019