La asincronía es uno de los pilares de Javascript, ya que se trata de un lenguaje de un sólo subproceso o hilo, lo que se conoce como single thread.

Procesamiento Single Thread y Multi Thread

Javascript es un lenguaje Single Thread. Imaginemos que solicitamos datos a una API, dependiendo de la situación de la red, el servidor, esto puede tardar poco o mucho tiempo, y mientras el hilo principal de nuestro código se quedaría bloqueado y la página web quedaría bloqueada, y aquí es donde entra la asincronía. Javascript fue diseñado para ser ejecutado en navegadores, trabajar con peticiones hacia la red y procesar las interaciones con el usuario, y esto tratando de mantener una interfaz fluida.

Trabaja bajo un modelo asíncrono y no bloqueante, y tiene un loop de eventos implementados de un solo hilo (Single Thread) para operaciones de entrada y salida.

Event loop en Javascript

Even Loop Javascript

Procesamiento

Los hilos (threads) son las unidades básicas de ejecución de cada proceso que realiza nuestra máquina. Cada vez que abrimos el navegador o un editor de código, en nuestra máquina se levanta un proceso, estos procesos pueden correr varios hilos o un sólo hilo, que es lo que ejecuta su funcionalidad. Hay lenguajes que trabajan en un solo hilo (single thread) o lenguajes que trabajan en multi hilos (multi thread).

Javascript trabaja bajo una filosofía llamada LIFO (Last In – First Out), lo último en entrar es lo primero en salir.

Operaciones de CPU y de entrada

En un procesamiento en el código de una aplicación podemos tener operaciones de este tipo, las operaciones de CPU son las que pasan el mayor tiempo consumiendo los procesos de nuestra CPU.

Las operaciones I/O son aquellas que pasan la mayor parte del tiempo esperando la petición del recurso que han solicitado (un formulario enviado a un servidor, un pago en línea, solicitar datos a una API como JSON…)

En Javascript podemos ejecutar ambas, pero en la mayoría de los casos utilizarán las operaciones de I/O.

Concurrencia y paralelismo

Concurrencia es cuando dos o más tareas progresan simultáneamente. Paralelismo es cuando dos o más tareas se ejecutan al mismo tiempo. La concurrencia podría parecer lo mismo, pero la clave está en la palabra ‘progresar’. Podemos tener concurrencias en un periodo síncrono o asíncrono.

Operación bloqueante y no bloqueante

Se refiere a la fase de espera cada vez que se ejecuta una operación. Una operación bloqueante es aquella que no devuelve el control a la aplicación hasta que haya terminado toda su tarea. La no bloqueante es que las operaciones se ejecutan y devuelven el control al hilo principal, no importando si ha terminado, mandará una notificación al hilo principal y en el caso de que se haya ejecutado mandará los datos o el mensaje correspondiente, y en caso contrario se podrá manejar un código de error.

Operaciones síncronas y asíncronas

Se refieren a cuando tendrá lugar la respuesta. Pensando en el presente, pasado y futuro, síncrono significa que la respuesta ocurre en el presente, asíncrono, la respuesta sucede en un futuro, se ejecuta pero no sabe cuando va a venir la respuesta, es por eso que suelta el control y se lo devuelve al hilo principal.

Puede haber código síncrono bloqueante y no bloqueante, el código asíncrono normalmente va a ser siempre no bloqueante.

2 tipos de código

En Javascript vamos a tener dos tipos de código:

  • Código síncrono bloqueante
  • Código asíncrono no bloqueante

En un código síncrono bloqueante, cada operación se hace de una vez, bloqueando el flujo del hilo principal, el cual queda bloqueado mientras espera la respuesta.

Ejm

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Operaciones síncronas y asíncronas</title>
  </head>

  <body>
    <h1>Operaciones síncronas y asíncronas</h1>

    <script>
      // CÓDIGO SÍNCRONO BLOQUEANTE
      (() => {
        console.log("Código síncrono");
        console.log("Inicio");
        function dos() {
          console.log("Dos");
        }

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

        uno();
        console.log("Fin");
      })();

      // CÓDIGO ASÍNCRONO NO BLOQUEANTE
      (() => {
        console.log("Código Asíncrono");
        console.log("Inicio");

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

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

        uno();
        console.log("Fin");
      })();
    </script>
  </body>
</html>

Resumen

Javascript usa un modelo asíncrono no bloqueante con un loop de eventos implementado en un sólo hilo (single thread) para operaciones de entrada y salida (input/output).