El JavaScript dentro de un navegador Chrome está implementado por el motor V8.
- El motor V8 tiene dos partes:
- Montón de memoria
- Pila de llamadas
Montón de memoria: se utiliza para asignar la memoria utilizada por su programa JavaScript. Recuerde que el montón de memoria no es lo mismo que las estructuras de datos del montón, son totalmente diferentes. Es el espacio libre dentro de su sistema operativo.
Pila de llamadas: dentro de la pila de llamadas, su código JS se lee y se ejecuta línea por línea.
Ahora, JavaScript es un lenguaje de subproceso único, lo que significa que solo tiene una pila de llamadas que se usa para ejecutar el programa. La pila de llamadas es la misma que la estructura de datos de la pila que puede leer en Estructuras de datos. Como sabemos, las pilas son FILO, es decir, primero en entrar, último en salir. De manera similar, dentro de la pila de llamadas, cada vez que una línea de código ingresa a la pila de llamadas, se ejecuta y sale de la pila. De esta forma, JavaScript es un lenguaje de un solo subproceso debido a una sola pila de llamadas.
JavaScript es un lenguaje de subproceso único porque, al ejecutar el código en un solo subproceso, puede ser muy fácil de implementar, ya que no tenemos que lidiar con los escenarios complicados que surgen en el entorno de subprocesos múltiples, como el punto muerto.
Dado que JavaScript es un lenguaje de subproceso único, es de naturaleza síncrona. Ahora, se preguntará si ha utilizado llamadas asíncronas en JavaScript, ¿entonces es posible?
Entonces, déjame explicarte el concepto de llamada asíncrona dentro de JavaScript y cómo es posible con un lenguaje de subproceso único. Antes de explicarlo, analicemos brevemente por qué requerimos la llamada asíncrona o las llamadas asíncronas. Como sabemos dentro de las llamadas síncronas, todo el trabajo se realiza línea por línea, es decir, primero se ejecuta una tarea y luego se ejecuta la segunda tarea, sin importar cuánto tiempo tome una tarea. Esto plantea el problema del desperdicio de tiempo, así como el desperdicio de recursos. Estos dos problemas se superan con las llamadas asincrónicas, en las que uno no espera a que se complete una llamada, sino que ejecuta otra tarea simultáneamente. Entonces, cuando tenemos que hacer cosas como el procesamiento de imágenes o realizar requests a través de la red, como llamadas API, usamos llamadas asíncronas.
Ahora, volviendo a la pregunta anterior sobre cómo usar la llamada asíncrona dentro de JS. Dentro de JS tenemos un entorno léxico, un analizador de sintaxis, un contexto de ejecución (montón de memoria y pila de llamadas) que se usa para ejecutar el código JS. Pero excepto que estos navegadores también tienen bucles de eventos, cola de devolución de llamada y WebAPI que también se usan para ejecutar el código JS. Aunque estos no son parte de JS, también ayudan a ejecutar JS correctamente, ya que a veces usamos las funciones del navegador dentro de JS.
Como puede ver en el diagrama anterior, DOM, AJAX y Timeout no son en realidad parte de JavaScript, sino parte del entorno RunTime o del navegador, por lo que se pueden ejecutar de forma asíncrona dentro de WebAPI utilizando la cola de devolución de llamada y colocarlos nuevamente en la pila de llamadas. usando el bucle de eventos para ejecutar.
Pongamos un ejemplo para tener muy claro el concepto. Supongamos que tenemos el siguiente fragmento de código que queremos ejecutar en el entorno de tiempo de ejecución de JS.
Ejemplo:
<script> console.log('A'); setTimeout(() => { console.log('B'); }, 3000); console.log('C'); </script>
Producción:
A C B
Veamos por qué sucede esto, ya que JavaScript es un lenguaje de subproceso único, por lo que la salida debería ser ABC , pero no lo es.
Cuando JS intenta ejecutar el programa anterior, coloca la primera declaración en la pila de llamadas que se ejecuta e imprime A en la consola y sale de la pila. Ahora, coloca la segunda declaración en la pila de llamadas y cuando intenta ejecutar la declaración, descubre que setTimeout() no pertenece a JS, por lo que muestra la función y coloca WebAPI para que se ejecute allí. Dado que la pila de llamadas ahora está nuevamente vacía, coloca la tercera declaración en la pila y la ejecuta, por lo que imprime C en la consola.
Mientras tanto, WebAPI ejecuta la función de tiempo de espera y coloca el código en la cola de devolución de llamada. El bucle de eventos verifica si la pila de llamadas está vacía o no, o si hay alguna declaración en la cola de devolución de llamada que deba ejecutarse todo el tiempo. Tan pronto como el bucle de eventos comprueba que la pila de llamadas está vacía y que hay algo en la cola de devolución de llamadas que debe ejecutarse, coloca la declaración en la pila de llamadas y la pila de llamadas ejecuta la declaración e imprime B en la consola del navegador.