¿Qué es el entorno de ejecución de javascript?

¿Qué es el entorno de ejecución de javascript?

Cuando hablamos de entorno de ejecución en ciencias de la computación nos podemos referir a muchas cosas, pero cuando lo usamos en este contexto nos referimos a las entidades con las que convive ( runtime system en inglés) el programa.

El entorno de ejecución es aquel comportamiento que no se le puede atribuir directamente al lenguaje de programación, pero que influyen en él.

Hacer separación entre el comportamiento que se le puede atribuir a un lenguaje y el que no, es difícil. Debido a que dadas ciertas circunstancias se podría considerar como algo externo y con otras como algo propio del lenguaje, por lo que no hay un consenso universal.

Pero en este blog voy a hablar de 4 características que en mi opinión son fundamentales en el entorno de ejecución de JavaScript

  • Es single-thread o un solo hilo
  • Event-loop
  • JS engines
  • Ejecución del código en el navegador y en el servidor con node.js

🛣️ Single threaded (un solo hilo)

Espera ¿Hilo? 🤨 ¿Qué tiene que ver twitter en todo esto? No querido amigo no estamos hablando de un hilo en Twitter, ni del hilo y aguja que usa tu abuelita para crearte una bufanda.

En ciencias de la computación un thread) es la cantidad más pequeña de secuencias de instrucciones programadas, que pueden ser manejadas independientemente por un planificador.

¿La cantidad más pequeña de que?😵‍💫 Bueno esa es la definición técnica, pero vamos a entender lo que dice.

Un programa para su ejecución se divide en múltiples partes para su ejecución de manera paralela, ¿Por qué se hace esto? Es simple, de otra manera no podrías tener tus 20 pestañas abiertas en chrome haciendo cosas diferentes cada una, solo podrías estar haciendo una cosa, por lo que solo podrías tener una sola pestaña.

Ahora un thread (hilo) es la forma más pequeña que tiene un proceso de dividir estás actividades, en el ejemplo anterior tendríamos una pestaña por thread (muy probablemente funcione diferente, es solo un ejemplo de analogía)

Entonces cuando decimos que un JavaScript es single thread (hilo) lo que estamos diciendo, es que tiene un solo thread para manejar todas las tareas que ejecutamos.

¿Entonces por que podemos ejecutar varias cosas a la vez en nuestro navegador? Por dos razones principales

  • El asincronismo de JavaScript
  • JavaScript no es el navegador y el navegador si utiliza múltiples hilos para funcionar.

El asincronismo surge por la necesidad de aprovechar de mejor manera nuestro único hilo que tenemos disponible ¿qué pasa si quiero realizar una tarea en la que solo tienes que esperar? Pues estaríamos desperdiciando demasiados recursos, es como si pusiéramos una lavadora y no hiciéramos otra cosa hasta que no acabe su proceso.

Para evitar tener que esperar hasta que la tarea finalice para poder continuar con la ejecución, usamos el asincronismo, que es la capacidad que tenemos de delegarle tareas a la API del navegador, mientras JavaScript sigue haciendo otras tareas y cuando termine sus tareas, verifica cuáles de las actividades delegadas han terminado para darle seguimiento.

Siguiendo con nuestra analogía de la lavadora, metemos la ropa e iniciamos el ciclo de lavado, mientras en paralelo barro y trapeo la casa y cuando termine estas actividades válido si el ciclo de la lavadora ya terminó para así sacar la ropa y colgarla.

Para lograr entender de una manera más técnica como funciona el asincronismo en JavaScript primero tenemos que entender que es el event loop ya que es lo que hace que funcione está particularidad del lenguaje,

🔄 Event loop

Es el proceso que maneja la delegación de tareas al navegador y darle seguimiento. ¿Pero para que necesitamos darle seguimiento a una tarea delegada?

Bueno imaginemos que queremos consultar información de una página externa, como debemos esperar la respuesta de un tercero y no sabemos cuánto tiempo nos tomará, sería buena idea delegar la consulta al navegador.

¿Pero cómo obtenemos la información otra vez en nuestro programa? Una vez que tengamos la información ¿qué proceso debemos de hacer?

Obviamente necesitamos una forma de gestionar esto y aquí es donde el event loop (ciclo de eventos) aparece. Para poder comprender cómo funciona, veamos cómo funcionan sus elementos que lo conforman.

📚 Call-stack (pila de ejecución)

Nuestro código cada vez que detecte una llamada a una función (call) la colocará en una pila( stack)), y si en esta función llamamos a otra la añadirá a la pila, así sucesivamente hasta que ya no llamemos a más funciones, entonces aquí comenzará a ejecutarlas una por una comenzando por la última.

Esto es algo confuso así que vamos a ilustrar este funcionamiento con un ejemplo.

Teniendo este código nuestro call stack se vería así paso a paso.

🌐 Web APIs

La web api es al quién le delegamos nuestras tareas, para que JavaScript pueda ejecutar otras tareas aprovechando de mejor manera los recursos ¿Pero cómo funciona?

Primero entendamos que es una application programming interface o interfaz de programación de aplicaciones( API ). Es un programa que nos permite comunicarnos entre aplicaciones desarrolladas por otras personas.

¿Por qué nos queríamos comunicar con otras aplicaciones? Muy sencillo, para evitar reinventar la rueda.

Imagina que estás desarrollando la página de un hotel, y te piden que despliegues un mapa del lugar. Si no existieran las apis, tú tendrías que desarrollar todo un sistema de geolocalización, pero como no es el caso, podemos comunicarnos con la API de Google y dejar que Google se encargue de ello.

Las Web APIs se dividen en dos categorías:

  • 💻APIs del navegador: son múltiples APIs integradas en tu navegador, que nos permite delegarle tareas. Esto tiene como finalidad

  • Lograr realizar tareas complejas los cuales no podríamos realizar usando solo JavaScript

  • Evitar quedarnos estancados en una tarea por mucho tiempo.

  • Aquí puedes ver una lista de todas las APIs disponibles en el navegador.

  • 🌐APIs de terceros: estas no están integradas al navegador. Son creadas por organizaciones ajenas al del navegador y tienes que obtener la información por medio de peticiones a sus APIs. El ejemplo que dí sobre la creación visual de un mapa con la ayuda de Google, es un claro ejemplo de una API de terceros.

Algo que no debes olvidar es que una vez delegada la tarea a una de estas APIs, JavaScript pierde conocimiento de esa tarea.

¿Entonces si JavaScript pierde todo el conocimiento como le damos continuación a las tareas delegadas al navegador? Bueno eso se logra gracias al call ¿back que

🔔 Call-back que (Cola de funciones de llamada de vuelta)

Ahora entendemos el proceso de delegación de tareas. Pero una vez que delegamos estas tareas ¿Cómo sabemos que se realizó correctamente o si fallo que hacemos? 🙇🏾‍♂️

Logramos realizar esto gracias a que al delegar una tarea, debemos pasar una función que se ejecutará cuando la tarea se haya terminado (función de llamada de vuelta o callback function).

Seguramente ahora te estarás preguntando cómo y cuándo se ejecutan estas funciones. Bueno para eso tenemos nuestra call-back que

Una vez que nuestra tarea delegada termina, manda la callback function a una cola. En la que esperará a que el call stack esté libre para ejecutar estas funciones. Tomando la que lleva más tiempo esperando.

Nota: de manera general y simplificando muchas situaciones, el call stack primero ejecutará (o lo delega) todo nuestro código escrito en nuestro archivo .js y luego comenzará a ejecutar las funciones callbacks .

⚙️Todos los elementos como un solo proceso

Ahora que entendemos los elementos que forman parte del event loop, veamos como funcionan juntos.

Primero se empieza a correr nuestro código con la ayuda del call stack, cuando se encuentra una tarea que debe de delegar la manda a una Web api con una callback function, dónde JavaScript pierde el conocimiento de esa tarea.

La web api se encarga de realizar la tarea, una vez que termina manda la callback function a una fila. Ahí esperará su turno para ser ejecutada.

Esta fila esperará a que el call stack no tenga tareas que ejecutar, para mandarle a ejecutar la callback function más antigua.

Y el event loop es este proceso que se itera esto una y otra vez, el cuál nos ayuda a manejar el asincronismo de JavaScript.

🏍️ JS Engines (motores de JavaScript)

Si le pasamos una máquina solo el código escrito en JavaScript será incapaz de entenderlo, una computadora solo entiende el lenguaje máquina.

Por lo que debemos pasar nuestro código por un programa que lo traduzca a lenguaje máquina.

🤔¿Entonces este programa traductor es el engine? No, ese programa sería el interprete) de JavaScript, que va traduciendo conforme el código conforme se va ejecutando y tan solo es un parte del motor de JavaScript.

¿Por qué no simplemente usamos el intérprete? Por que JavaScript por su diseño es muy lento, así que debemos de buscar una manera de optimizarlo. Aquí es donde entra el motor de JavaScript.

El motor de JavaScript no solo se encarga de traducir nuestro código a lenguaje máquina, también se encarga de optimizarlo, por qué el lenguaje por sí solo es muy lento.

De hecho la mayoría de los navegadores tiene su propio motor, pero debido a que JavaScript es un estándar todos funcionan de una manera similar.

¿Pero cómo funciona? Bueno el funcionamiento exacto depende de cada motor, pero todos funcionan de una manera similar, así que veamos de manera breve el funcionamiento del motor V8 uno de los más populares.

La ejecución de nuestro código la podemos dividir en dos partes:

  • Ignition interpreter (interprete de encendido): En este paso el motor optimiza nuestro código (lo convierte a bytecode) para que se más fácil su interpretación. Posteriormente lo pasa a un interprete) y lo ejecuta.
  • Optimization compiler (compilador de optimización): Este proceso corre en paralelo y su objetivo es optimizar nuestro código, el motor empieza a buscar las partes que le cuesta más trabajo ejecutar al cpu (hot code), lo optimiza y lo traduce completamente a lenguaje máquina (lo compila).

Esto último se hace porque es más rápido su ejecución si el código está completamente traducido (compilarlo) que traducirlo línea por línea para lograr su ejecución (interpretarlo).

¿Pero si es más rápido interpretarlo que compilarlo por qué se interpreta? Por qué la prioridad número uno del motor es comenzar a ejecutar el código. Por lo que el motor sacrifica rapidez de inicio, por rapidez de ejecución

Pensemos un momento en las cosas con las que interactúa JavaScript cuando lo corremos en el navegador está el DOM, APIs, nuestros clicks constantes desesperados por que se nos trabo la página 🤷🏾‍♂️ …

Obviamente cuando ejecutamos JavaScript en node, no tiene que interactuar con estas cosas. Node interactúa con los procesos de entrada y salida de datos, las peticiones de los clientes, los procesos del sistema operativo, entre otras.

Y está es la parte importante, recuerda que el runtime no es más que las entidades con las que convive. Por lo que JavaScript estaría trabajando con conceptos diferentes.

Incluso el event loop se comporta de manera diferente en el navegador que en el servidor. Pero eso es tema para otro blog.

🔖Resumén

Cuando hablamos de un entorno de ejecución de un lenguaje (runtime system), nos referimos a las partes que no se le pueden atribuir directamente al lenguaje, pero que afecta la ejecución de nuestro programa.

En el caso de JavaScript, tenemos a el event loop el cuál es el proceso que nos ayuda a manejar el asincronismo, los motores que es quién nos ayuda a correr y optimizar nuestro código.

Por último tenemos al lugar en donde corremos JavaScript (en un servidor o en un navegador). Al cambiar las entidades con las que convive JavaScript tiene diferencias sutiles cuando lo ejecutamos en el navegador y en el servidor.

Referencias

A JavaScript runtime? What is it? por Ishwar Rimal
What is the JavaScript runtime? por Nicholas Mendez
Runtime system Wikipedia
Thread Wikipedia
Wha is an api? por IBM Cloud Education
Introduction to web APIs por mdn web docs
How JavaScript Works behind the scenes? por Aditya Yaduvanshi
How JavaScript engines achieve great performance por Robin Heggelund Hansen
How does JavaScript and JavaScript engine work in the browser and node? por Uday Hiwarale

Recomendaciones

Help, I’m stuck in an event-loop. Es un video de una charla de Philip Roberts, donde explica de una manera fenomenal el event loop.

Loupe herramienta creada por Philip Roberts, para explicar el event loop de una manera visual.