Asincronismo con Javascript

La asincronía es uno de los pilares de Javascript, ya que es un lenguaje de un solo hilo (single thread), es decir que puede ejecutar solo una cosa a la vez. Entonces, ¿qué pasa si queremos solicitar datos de una API?, puede pasar que el servidor tarde cierto tiempo en procesar la solicitud, mientras nuestro programa queda bloqueado esperando la respuesta del servidor. ¿Y ahora que hago?, ¿solo me queda esperar a que llegue la respuesta para seguir?. Bueno, acá es donde entra en juego la asincronía, que nos permite hacer solicitudes sin bloquear la ejecución del programa.

Javascript utiliza un modelo asincrónico y no bloqueante. Esto nos permite realizar operaciones sin la necesidad
de esperar el resultado de ésta para poder seguir ejecutando otras tareas.

Pero antes, veamos un ejemplo de como funciona el motor v8 que utiliza Chrome.

 

Memory Heap: hace referencia a la parte de la memoria no estructurada donde se guardan los objetos y funciones.
Call Stack: es donde el motor mantiene las llamadas a las funciones y utiliza el método LIFO (Last In, First Out). De este modo, cuando se está a punto de ejecutar una función, ésta se agrega al stack. Si a su vez la función llama a otra función, es agregada sobre la anterior, y ésta ultima será ejecutada antes de que finalice la otra.

//Ejemplo sincronico
function uno() {
console.log("Uno");
dos();
console.log("Tres");
}

function dos() {
console.log("Dos");
}

console.log("Iniciando");
uno();
console.log("Finalizando");

//Este programa retorna:
Iniciando proceso
Uno
Dos
Tres
Finalizando proceso

En éste caso, se va llenando y vaciando el call stack a medida que vamos ejecutando las funciones de manera sincrónica. Las salidas del programa, se van mostrando una vez que finaliza la instrucción anterior.

Pero que pasa si queremos llamar a un timeout o hacer una petición con Ajax a un servidor?
Al tener un solo hilo, solo tenemos un call stack y por tal motivo deberóamos esperar a que una ejecución termine para continuar con otra. Sin embargo, ésto no es un problema con Javascript, gracias al Event loop.

En la siguiente foto podemos ver una forma mas amplia de Javascript, donde no solo tenemos el motor V8 sino que también tenemos las Web APIs y el callback queue. Asi es como por ejemplo, si queremos hacer una llamada Ajax, podemos continuar con la ejecución del programa mientras esperamos la respuesta de éste, o que se ejecute un setTimeOut y podamos seguir operando mientras el tiempo configurado finaliza.

 

 

Veamos el siguiente ejemplo:

function uno() {
setTimeout(function () {
console.log("Uno");
}, 0);
dos();
console.log("Tres");
}

function dos() {
setTimeout(function () {
console.log("Dos");
}, 3000);
}

console.log("Iniciando proceso");
uno();
console.log("Finalizando proceso");

//Este programa retorna:
Iniciando proceso
Tres
Finalizando proceso
Uno
Dos

Como podemos ver, primero se ejecuta console.log("Iniciando"). Luego se agrega al stack la función uno() y se muestra tres. Pero como ¿tres?, ¿no debería mostrar primero uno y dos?. Bueno, acá es donde empieza a jugar la Web Api setTimeOut y el Callback Queue. Una vez que se llama al setTimeOut de uno y dos, el programa se sigue ejecutando mientras se esperan sus respuestas, una vez que éstas llegan, se encolan en el Callback Queue hasta que se ejecuta console.log("Finalizando proceso") y el Call Stack quede totalmente vacío. Finalmente se empiezan a cargar las funciones que quedaron pendientes.
Podemos notar que ésto ocurre independientemente del tiempo configurado en el timeout, aunque se haya configurado en 0, éste no se ejecuta instantaneamente sino que igualmente se encola en el Callback Queue.
Javascript cuenta con algunos mecanismos para controlar la asincronía (Callbacks, Promises, Async/Await) los cuales veremos mas en detalle en otros artículos.

AJAX

AJAX significa Asynchronous JavaScript And XML. Es una técnica que utiliza el objeto XMLHttpRequest para comunicarse con los servidores.
Puede enviar y recibir información en varios formatos, como por ejemplo JSON, XML, HTML e inclusive archivos de texto.
La ventaja de Ajax es que su naturaleza asincrónica, lo que nos permite comunicarnos con un servidor, enviar, recibir o actualizar datos sin necesidad de que recarguemos la pagina.

 

XMLHttpRequest API

XMLHttpRequest es un objeto JavaScript que nos facilita obtener información de una URL sin tener que recargar la página completa, al igual que el Fetch API el cual veremos
en un siguiente articulo. Para crear una instancia de XMLHttpRequest, lo haremos de la siguiente manera:

var xhr = new XMLHttpRequest();

Este objeto contiene propiedades y metodos que nos permiten comunicarnos asincronicamente con otro servidor a traves del protocolo HTTP.

  • ReadyState

Si vemos nuestro objeto xhr recientemente creado, todas sus propiedades se van a encontrar vacías con null, undefined, 0 o con un String vacío, esto pasa porque el objeto aun no esta configurado para enviar una peticion.
La propiedades readyState, nos muestra el estado en el que se encuentra una solicitud y puede tomar alguno de los siguientes valores.

 0 (UNSET)  Objeto inicializado
 1 (OPENED)  Objeto configurado
 2 (HEADERS_RECEIVED)  El objeto ya se envío y el status de los headers del servidor ya   volvieron
 3 (LOADING)  La propiedad responseText mantiene datos parciales
 4 (DONE)  La operación se completó (no necesariamente con éxito)
  • Open

Este método nos permite configurar una solicitud saliente.

XMLHttpRequest.open(String metodo, String url[, Boolean async]);

Recibe como parámetros obligatorios el método HTTP y la URL al cual vamos a enviar. El tercer parámetro opcional es un booleano
que determina si la solicitud va a ser sincrónica o asincrónica.
Hasta acá, solo tenemos el objeto xhr configurado, pero aun no lo enviamos.

  • ReadyStateChange

Este evento se dispara cada vez que la propiedad readyState del objeto xhr cambia, es decir que podemos tener el control total
sobre cada uno de los estados del pedido.

  • Load

El evento load se dispara cuando la propiedad readyState es igual a 4. Esto no quiere decir necesariamente que la operacion se haya completado
exitosamente, asi que para asegurarnos de eso, podríamos consultar si el status del objeto xhr es por ejemplo un 200.

  • Response

Una vez que la respuesta haya llegado y se descargue la información, podríamos manejarla o asignarla a cualquier elemento mediante la propiedad response.

  • Send

Este método, nos permite enviar el pedido una vez que se encuentre configurado. Veamos un simple ejemplo usando todo lo mencionado anteriormente. Tenemos un botón, que si le hacemos click hacemos un pedido ajax a un api de usuarios y el
resultado se muestra dentro del div.

let boton = document.getElementById("boton");

boton.addEventListener("click", () => {
let ajax = new XMLHttpRequest();
ajax.open("GET", "https://jsonplaceholder.typicode.com/users");

ajax.addEventListener("load", () => {
if (ajax.status == 200 ){
let div = document.createElement("div");
let listaUsuarios = ajax.response;
div.innerHTML = listaUsuarios;
document.body.appendChild(div);
}
});
ajax.send();
});

Mandanos tus sugerencias

Ayudanos con ideas para los artículos de este blog a contacto@somospnt.com

¡Seguínos en nuestras redes sociales para enterarte de los últimos posts!