JavaScript asincrónico

Agenda

  1. ¿Que es asincronía?
  2. Funciones callback
  3. setTimeout y setInterval
  4. AJAX, XHR
  5. Promesas y API fetch
  6. async / await

¿Que es asincronía?

Para entender asincronía en JavaScript, primero tengamos claro lo opuesto

Cambiemos momentáneamente la pregunta: ¿Qué es JavaScript síncrono?

Lo que han visto hasta ahora, es todo código síncrono. La ejecución se realiza en orden. Una sentencia se ejecuta una vez que la anterior finaliza, de arriba a abajo.

              console.log('Primer salida a consola');
              console.log('Segunda salida a consola');
          

Ejecutar código de manera síncrona nos impone algunas limitantes con operaciones lentas, costosas o ejecutadas por terceros. Veamos el siguiente código.


                const btn = document.querySelector('button');
                btn.addEventListener('click', function () {
                  let fecha;
                  for (let i = 0; i < 10000000; i++) {
                    fecha = new Date();
                  }
                  let pElem = document.createElement('p');
                  pElem.textContent = fecha;
                  document.body.appendChild(pElem);
                });
            
Para evitar el código bloqueante, por ejemplo para no congelar el navegador mientras pedimos información a un servidor, hacemos uso de código que corre de forma asíncrona.

Callbacks

Una función callback es aquella que es pasada por parámetro a otra función o asignada a un atributo, para luego ser invocada.

            const saludo = function (nombre) {
              alert('Hola ' + nombre);
            };

            function pedirNombre(callback) {
              let nombre = prompt('Por favor ingresa tu nombre');
              callback(nombre);
            };

            pedirNombre(saludo);
          
Podemos manejar eventos del DOM utilizando callbacks.

            function callback(event) {
              event.preventDefault();
              console.log("El usuario hizo click en el botón!");
            };

            const boton = document.queryselector("#callback-btn")
            
            boton.addEventListener("click", callback);
          

setTimeout - setInterval

Son funciones que nos provee JavaScript y nos permiten ejecutar funciones de manera asincrónica. Ambas reciben por parámetro la función (callback) que deben ejecutar.

setTimeout

Recibe como primer parámetro la función callback, y como segundo parámetro el tiempo que debe esperar para realizar la invocación a la función (expresado en milisegundos).

            function myFunction() {
              console.log("Han pasado 3 segundos!");
            };

            setTimeout(myFunction, 3000);
          

setInterval

Recibe como primer parámetro la función callback, y como segundo parámetro el tiempo que debe esperar entre cada invocación a la función (expresado en milisegundos).

            let counter = 0;
            function incrementCounter() {
              counter = counter + 1;
              console.log('Esta función se ejecutó ' + counter + ' veces!');
            };

            setInterval(incrementCounter, 1000);
          

setTimeout - setInterval

Puede suceder que necesitemos que nuestro timer no se siga ejecutando. Para ello podemos utilizar la función clearTimeout o clearInterval.

            let counter = 0;
            let timer;

            function incrementCounter() {
              counter = counter + 1;
              checkCount();
            };

            function checkCount() {
              if (counter == 10) {
                clearInterval(timer);
              };
            };

            timer = setInterval(incrementCounter, 1000);
          

AJAX

Es una técnica utilizada para poder cambiar contenido dinámicamente en una aplicación web. El contenido es modificado sin necesidad de recargar la página o interrumpir su comportamiento.
Esto se realiza pidiendo datos a un servidor asincrónicamente. Cuando el servidor responde con los datos solicitados, se utiliza Javascript para modificar el contenido con esta nueva información.

XHR

Se utiliza XHR (sigla para XMLHttpRequest) para ejecutar AJAX en páginas web.

XHR

Request AJAX utilizando método 'GET'

            const xhr = new XMLHttpRequest();
            xhr.open('GET', 'https://api.com/datos');
          
            // Callback al finalizar correctamente
            xhr.onload = function () {
              // convertir respuesta a JSON a partir del texto
              const response = JSON.parse(xhr.responseText);
              console.log(response);
            }

            // Callback de error en el request.
            xhr.onerror = function () {
              console.log('Error: ' + xhr.statusText); 
            };
          
            // Enviar el request hacia el servidor
            xhr.send();
          

Promesas

Una promesa es un objeto que representa el estado de una operación asíncrona. El navegador nos promete retornar una respuesta cuando la reciba, si la recibe

Para usar una promesa, asociamos callbacks a los métodos disponibles. Al cambiar el estado de la promesa, se ejecutarán los callbacks correspondientes.

Estos callbacks se invocarán con los datos buscados o información sobre el error ocurrido como parámetros

Los métodos son:

Estos metodos pueden a su vez encadenarse, dado que retornan a su vez promesas. Los callbacks sobre estos métodos, pueden retornar valores y estarán disponibles para los siguientes en la cadena.

Ejemplo abstracto

            promesa
            .then(callbackExito)
            .catch(callbackError)
            .finally(callbackFinal);
          
Un buen ejemplo de uso de promesas es la API fetch. Esta facilita el manejo de peticiones y respuestas a un servidor, en comparación con XHR.

            const promesa = fetch("https://api.com/datos");
            
            promesa
            .then(function (respuesta) {
                return respuesta.json();
            })
            .then(function (data){
                console.log(data);
            })
          
También podemos crear nuestra propia promesa. Simulemos tirar una moneda.

            const moneda = new Promise(
              function(resolve, reject){
                if (Math.random() > 0.5){
                  resolve('cara!');
                }
                reject('cruz!');
              }
            );

            moneda
            .then(console.log)
            .catch(console.log);
          

async / await

Declarar funciones como async nos permite usar una sintaxis más simple para utilizar promesas, habilitándonos el uso de la palabra clave await.

El código luce como si fuera síncrono!

La palabra clave await nos permite esperar, de manera asíncrona, a la respuesta de una promesa.

La palabra clave async, define una función asíncrona, y nos habilita a usar la palabra clave await.

Reescribamos esta función con promesas usando async/await

              function obtenerDatos() {
                const promesa = fetch("https://api.com/datos");
                promesa.then(function (respuesta) {
                    return respuesta.json();
                }).then(function (data){
                    console.log(data);
                })
              }
            

              async function obtenerDatos() {
                const respuesta = await fetch("https://api.com/datos");
                const data = await respuesta.json();
                console.log(data);
              }
            

Los rechazos en nuestras promesas, usando async/await también lucen como código síncrono.

Usamos un bloque try/catch para capturar los errores, de la misma forma que lo haríamos con excepciones.


            async function obtenerDatos() {
              try {
                const respuesta = await fetch("https://api.com/datos");
                const data = await respuesta.json();
                console.log(data);
              }
              catch(error) {
                console.log(error.message);
              }
            }
          

Tarea

Entrar al siguiente link para realizar la tarea

Ejercicio

Solución