Callbacks, Promesas y Async/Await, ¡Que alguien me explique!

En el desarrollo de sitios o aplicativos web es muy común realizar consultas a Application Programming Interface(API) estas pueden ser propias o de terceros, lo cual al final del día se puede traducir como una petición al servidor, dicha petición se realiza utilizando funciones de JavaScript de las cuales algunas presentan asincronía.

De una manera más concreta, las funciones que realizan operaciones de entrada/salida como pueden ser peticiones a servidores, lectura y escritura de archivos del disco.

¿Que es asincronía?

Asincronía: acción que no tiene lugar en total correspondencia temporal con otra acción. (Fuente: Wikipedia).

El cual se podría resumirse como “acciones que no se realizan en la misma línea de tiempo”.

Manos a la obra

Después de un poco de teoría empecemos con lo divertido, hablemos de código, (la codificación de los ejemplos será realizará en EmacScript 6 o 262). Actualmente JavaScript consta de diversas técnicas que permiten resolver la asincronía, cada una con sus propias diferencias.

CallBacks

Es una de las técnicas y forma más común para el control de la asincronía dentro de JavaScript, dicha técnica consiste en los siguientes pasos.

  1. - Se genera una función A de la que uno de sus argumentos es una función B que por convención recibe el nombre de callback.
  2. El callback recibe 2 argumentos, el primer argumento es una referencia a un error el cual puede ser personalizado o es generado por nuestro aplicativo, el segundo argumento contiene el resultado de la función A que está recibiendo el callback.

para conseguir una idea más clara analizemos el siguiente ejemplo.

Ejemplo básico del manejo de Callbacks (Fig-01)

Revisando el ejemplo anterior podemos apreciar que cumple con las reglas básicas del uso de la técnica mencionada con anterioridad, a primera vista podríamos considerarlo como una muy buena opcion para resolver la asincronía que presenta JavaScript, pero puede que no lo sea ya que podemos tener problemas mas adelante.

Tomando en cuenta todo lo anterior realicemos un ejemplo más robusto donde consultemos una API se realizarán múltiples peticiones mediante Asynchronous JavaScript And XML(AJAX), este ejemplo consistirá en.

  1. Consultar el API de pokémon para conseguir los datos de charmander.
  2. Con la data obtenida realizaremos múltiples consultas a la API para ir consiguiendo las evoluciones de nuestro pokémon.
  3. Usaremos la técnica de callbacks.
Fases de evolución de Charmander (Fig-02)
Consultando la Api de Pokemons usando CallBacks (Fig-03)

Analizando el ejemplo anterior, se puede observar que conforme se realizan peticiones a la API estas se van anidando una dentro de otra, este comportamiento podría repetirse con forme se requiera realizar peticiones al servidor lo que daría como resultado el temido CallBackHell tambien conocido como PyramidOfDoom.

Representación de CallBackHell o Pyramid of Doom (Fig-04)

Este problema surge por los niveles de profundidad que se generan en el código lo cual dificultara la lectura y el mantenimiento de este.

Nota: existen múltiples librería que nos pueden ayudar en el manejo de la asincrónica y evitar el CallBackHell, alguna de las librerías más comunes son q, async

Para nuestra buena suerte, con las nuevas especificaciones de EcmaScript 6 surge una nueva forma para el manejo de la asincronía.

Promesas

Esta es una de las nuevas técnicas que la comunidad está adoptando para solucionar el problema de asincronía que presenta JavaScript, dicha técnica consiste en la creación de un objeto Promise que recibe 2 parámetros los cuales son.

resolve : Este contendrá el resultado de la función que se está ejecutando dentro de la promesa.

reject : Contendrá una respuesta de error siempre y cuando no se pueda resolver la promesa.

Para tener una idea mas clara analizemos el siguiente ejemplo.

Ejemplo básico del manejo de Promesas (Fig-05)

En el ejemplo anterior podemos apreciar el uso básico de una promesas, pero lo interesante está que al ejecutar la función (asincroni) surgen dos nuevas funciones las cuales son.

then : Se ejecuta cuando la promesa es resuelta satisfactoriamente, tambien nos permite encolar código, esto lo podremos apreciar en el ejemplo que realizaremos.
catch : Se ejecuta cuando la promesa no puede resolverse de una manera satisfactoria podríamos decir cuando surge un error.

Para tener una idea más claro del manejo de promesas realizaremos el mismo ejemplo donde consultamos la API de pokemon, la diferencia radica en que no usaremos CallBacks serán sustituidos por promesas.

Consultando la Api de Pokemons usando Promesas (Fig-06)

Analizando el ejemplo anterior podemos apreciar algunas mejoras en la codificación de las cuales destacan.

1.- La función inicial (usandoPromesas) no requiere que se le pase un callback, para resolver la asincronía.
2.- Para el envió de las respuesta se utiliza resolve(respuesta satisfactoria) y reject(Error).
3.- La función inicial retorna una promesa.
4.- Conforme necesitemos realizar peticiones al servidor podemos ponerlas en cola usando then.
5.-Para el manejo de los errores solo se utilizará un catch el cual resolverá el error de cualquiera de nuestra peticiones.
6.- Desaparece el temido CallBackHell tambien conocido como PyramidOfDoom, por lo que el código es más fácil de mantener y leer.
7.- No siempre un then puede regresar una promesa, pero aun así podemos encolar código (ver linea 98).

Como se puede ver a simple vista al utilizar promesas podemos ver una mejora muy grande, existe otra forma para solucionar el problema de asincronía que presenta JavaScript.

Funciones Async/Await

Este tipo de funciones son una de las opciones más nuevas que presenta JavaScript para sus nuevas especificaciones de EmacScript 7, Async/Await a un no se soportado por los navegadores :( además aún se está evaluando la posibilidad de introducirla en JS :(, pero existe una opcion que nos permite probar esta nueva funcionalidad, esta opcion es BABEL que mediante sus librerías no permite utilizar la nueva generación de JavaScript hoy(eslogan del sitio).

Tomando en cuenta lo anterior inicializamos nuestro nuevo ejemplo usando Async/Awiat.

  1. Contar con una instalación de node.
  2. Descargar el ejemplo AsyncAwaitEjemplo.
  3. Desde la consola del Sistema Operativo entrar en la carpeta de nuestro ejemplo descargado y ejecutar el comando.
npm i

Este comando iniciará la instalación de las librerías que se utilizaran para que nuestro ejemplo se ejecute correctamente, al terminar la instalación tendremos una nueva carpeta llamada node_modules tambien tendremos el archivo index-build.js.

4. Al terminar la instalación, abre en tu navegador el archivo index.html, si todo sale bien tendrías que ver algo como esto (dar click en RunPen).

Ejemplo de AsyncAwait (Fig-07)

una pregunta que te puedes estar realizando es ¿Que es lo que pasó?, ¿Que demonios hicieron?, ¿Tiene algún pacto con el diablo robot? Muahaha.

Diablo Robot personaje de futurama (Fig-08)

Para poder entender todo lo que se realizó iniciaremos revisando los archivos del proyecto descargado.

Package.json

Manifiesto del aplicativo, contiene data general del autor, tambien tiene las referencias para los módulos que se utilizan, tiene un apartado de comandos en este caso estamos utilizando “postinstall este comando se ejecuta la terminar la instalacion”, para mas informacion consultar npm-scripts.

gulpfiles.js

Este archivo permitirá generar el paquete necesario para nuestra app.

Archivo gulpfile (Fig-10)

index.js

Este contiene toda la lógica de nuestro ejemplo que consulta la Api de pokemon, de este archivo podemos destacar que se inicia el uso de.

async : Permite identificar que una funcion sera síncrona.
await : Esto nos indicará donde se genera la pausa del flujo del programa.
fetch : Permite realizar la peticion al servidor esta funcion reemplaza “ XMLHttpRequest()”.
reponse.json: Permite realizar el parseo de la respuesta obtenida, el response es la variable que toma el valor que regresa fetch.
babel-poly-fill: Para poder utilizar nuevas funciones de EcmaScript ya que nos permite invocar el runtime generator.
Ejemplo del uso de Async/Await (Fig-10)

Como podemos nuestro ejemplo ya luce como una función síncronia, no es necesario usar promesas o callbacks, tambien es más fácil dar mantenimiento al código y el manejo de los errores se puede realizar utilizando try/catch.

Conclusión

JavaScript consta de diversas formas para resolver el problema de asincronía, cada una tiene sus pros y contras.

Entradas Recomendadas