Muchas veces uno escucha de varios términos de JS que puede ser uno no llegue a comprender del todo: runtime environments (ambientes de ejecución), versiones de EcmaScript…engines (motores).
¿Pero qué es exactamente un motor cuando hablamos de programación?
En la vida real cuando hablamos de motores hablamos de la parte de la maquinaria que que se encarga de transformar alguna clase de energía (como la energía eléctrica o los combustibles fósiles) en energía mecánica. El propósito por supuesto es utilizar esa energía mecánica para hacer trabajar dicha maquinaria.
¿Entonces…podemos asumir que en software es lo mismo?
Bueno, como te podrás imaginar no se transforma ninguna forma de energía para “activar” un pedazo de código. Pero si hay una transformación de ciertas partes para poner a trabajar nuestro software.
¿Qué es un engine?
En pocas palabras. Un engine es un programa (comúnmente un interpretador) que lee el código fuente, produce código máquina/binario y finalmente lo ejecuta. El código fuente es comúnmente referido como lenguaje de alto nivel y el código binario como lenguaje de bajo nivel.
*Esto aplica para cualquiera lenguaje de programación. No solo para Javascript.
Pausa. Si esos fue demasiada terminología debes primero entender las diferencias entre un lenguaje compilado e interpretado.
¿Listo? ¿Entendiste lo anterior sin problemas? Continuemos.
Dicho esto en Javascript es común que se digan que varios actores diferentes son los encargados de realizar este proceso de conversión a código máquina:
- El navegador
- El runtime environment (ambiente de ejecución)
- El engine (el que digo yo)
¿Entonces? ¿Quién te esta mintiendo?
Pues la realidad es que nadie.
Aqui caemos en un tipico problema de uso de terminología. Si no entendemos todo es fácil que podamos confundirnos.
Lo que ocurre es que un engine es uno de los varios componentes que conforman un Runtime Environment. Por lo tanto cuando dices que el Runtime Environment produce el código máquina es cierto, porque lo hace a través de su engine.
Por otra parte Runtime Environment es el nombre que se le da al lugar encargado de ejecutar código. En el caso de la web los navegadores ocupan este rol. Por lo tanto un navegador es un Runtime Environment.
*Porsupuesto el engine no es el único componente importante. Hay otras partes que conforman al Runtime Environment.
Las partes de un engine
Un engine esta compuesto de 2 elementos extremedamente importantes:
- Call Stack (Pila de Llamadas)
- Memory Heap (Memoria de Almacenamiento Libre)
Primero que nada debes recordar que Javascript es un lenguage single-threaded (de un hilo). Esto quiere decir que es un lenguaje que solo trabaja con un hilo de ejecución y por ende solo puede parsear el código línea por línea. El comportamiento hace que siempre exista el riesgo de que un script terminé bloqueandose a sí mismo por algun fallo en la lógica, como un loop infinito o una subrutina interminable.
Teniendo esto en cuenta te podrás imaginar que JS deberá tener una forma de mantener el orden de ejecución. Y ahí es donde entran estos 2 conceptos:
Call Stack (Pila de Llamadas)
La Call Stack es una pila que se encarga de mantener el orden en el que se deben ejecutar los Execution Context (contextos de ejecución) que se vayan creando durante la ejecución del código. Un Execution Context puede verse como la sección de código que se crea al ir ejecutando funciones en un script.
*Si quieres saber más de los Execution Context, te recomiendo que heches un vistazo a los conceptos de Global Execution Context y a Function Execution Context.
Memory Heap (Memoria de Almacenamiento Libre)
La Memory Heap por su parte es la encargada de mantener en memoria los valores y referencias que se esten utilizando en el Execution Context.
Las fases de un engine
Ahora ya sabes qués es un engine. ¿Pero cómo funciona?
Todos los engines (sean de Javascript o de algun otro lenguaje) hacen que el código pase por 3 fases:
- Parseo
- La interpretación de cada palabra clave y valor. Verificando que este estructurado correctamente.
- Compilación
- La conversión del código ya verificado a código binario.
- Ejecución
- Correr el código en el Runtime Environment
Porsupuesto cada fase conlleva mucho mas trabajo que se hace tras bambalinas. Trabajo que precisamente hace uso de la Call Stack y el Memory Heap.