El Call Stack consiste en ordenar las funciones que son invocadas de arriba hacia abajo, donde la última tarea será la que se ejecute primero. Una vez se ha guardado la información del archivo o programa, es momento de ejecutarlas.
Primeramente, guarda todas las funciones o declaraciones en anonymous que representa el objeto global.
Y así sucesivamente. Va agregando y quitando ejecuciones en el orden correspondiente. Es por eso que JavaScript realiza una tarea a la vez.
Ejemplo de ejecución
El siguiente código contiene tres funciones hello, world y main que ya han sido guardadas en el memory heap al declararlas y están listas para ejecutarse.
Al llegar a la función main, el Engine lo coloca en el Call Stack para ejecutarlo. Pero dentro se encuentran más invocaciones a otras funciones, por ende, primero ejecutará la que esté más arriba hasta ejecutarlas todas.
Al invocar la función hello, el Engine lo coloca en el Call Stack. La función console.log también es una función, por lo que el Engine también lo colocará en el Call Stack.
Una vez ejecutada la función console.log el Engine lo sacará del Call Stack.
Como la función hello ya ha sido ejecutada, el Engine lo sacará del Call Stack para seguir ejecutando la función main.
Y así sucesivamente, hasta que termine de ejecutarse main, o todas las tareas en el Call Stack. Cuando no existan tareas en el Call Stack, el programa habrá finalizado.
Hola! Lo tomé del articulo de medium Understanding Javascript Function Executions — Call Stack, Event Loop , Tasks & more en se detallan los temas tratados en el curso :smile:
El Call Stack es un mecanismo para que un intérprete realice un seguimiento de su lugar en un script que llama a múltiples funciones: qué función se está ejecutando actualmente y qué funciones se invocan desde esa función, etc.
Cuando un script llama a una función, el intérprete la agrega a la pila de llamadas y luego comienza a llevar a cabo la función. Cualquier función llamada por esa función se agrega a la pila de llamadas más arriba y se ejecuta donde se alcanzan sus llamadas. Cuando finaliza la función actual, el intérprete la quita de la pila y reanuda la ejecución donde la dejó en la última lista de códigos. Si la pila ocupa más espacio del que le había asignado, se produce un error de "desbordamiento de pila".
Puedes realizar el mismo ejercicio que el profesor en Firefox, solo debes escribir el código tal cual esta y cuando lo ejecutes el debugger te llevará a el depurador, que tiene una interfaz similar al de las devtools de chrome. (Es posible que en el depurador de firefox, el panel donde esta el call stack o pila de llamadas, este oculto y debas darle click a un boton a la derecha para mostrarlo), para avanzar en la ejecución y ver el paso a paso hay un control con flechas.
.
Funcionamiento del call stack, (en firefox: pila de llamadas)
.
Primero siempre se carga al call stack el objeto global, ya que a partir de el siguen las siguientes llamadas, cada vez que una función o tarea llama a otra esta se coloca un nivel por encima de la llamante en el call stack, la última función en entrar se resuelve y devuelve a su llamante inmediatamente debajo de esta, por ejemplo:
.
Al ejecutar el bloque de código siguiente, el motor de javascript realizará todas las operaciones previas a la ejecución del código (a grandes rasgos el parseo, interpretación y compilado), y detendrá todo en el debugger.
.
En el debugger antes de llamar a calcular() se puede observar a la izquierda que la pila de llamadas "call stack" tiene al objeto global creado, y listo para ejecución.
.
.
El objeto global realiza la llamada a calcular(), y esta se pasa a la pila de llamadas, por encima de su llamante, calcular comienza a ejecutarse, llegará a la linea 6 donde debe llamar a otra funcion.
.
.
calcular() llama a restarDos(num), y se observa que se le pasa como valor lo sumado previamente, podemos observar que restarDos(num) esta en la pila de llamadas por encima de su llamante.
.
.
Cuando restarDos(num) termina, devuelve su resultado y por lo tanto el control de la ejecución a calcular(), que a su vez tambien termina.
.
.
Por último el control es devuelto al objeto global, este a su vez retorna por consola el resultado del código ejecutado, al no haber mas tareas el call stack queda vacio.
Es importante recordar que en el call stack las tareas a resolver se van apilando, y cuando se resuelven con éxito se van desapilando y devolviendo el control a su llamante, hasta alcanzar el objeto global.
.
Esto es lo que he entendido del tema, espero sea de ayuda. Si me equivoque en algo o no se entiende bien los leo en comentarios :)
No, la pila de tareas no es el event loop. Son diferentes.
El call stack, como ya sabes, es el encargado de ir llamando y ordenando a las funciones para que estas sean ejecutadas. En el call stack las funciones se van agregando al final de la pila, y las de arriba de la pila se van ejecutando y borrando del call stack.
Ahora bien, lo que hace el event loop, en un lenguaje muy coloquial, es observar en todo momento al call stack ¿para qué? para saber si este está vacío o no. En caso de que esté vacío enviará la primera función que vea en el callback queue al call stack para que ésta comience a ejecutarse. Y hasta ahí todo bien, pero ¿que es callback queue? este callback es el encargado de guardar los llamados a las Web APIs¹ para que cuando el call stack este vacío enviarlos allí mediante el event loop y ejecutarlos.
Y así es como para mi todos los conceptos se unen y todo cobra sentido :D
Te dejo una imagen que resume perfectamente lo que traté de explicarte:
¹ Una Web API es una función que no hace parte de directamente de JavaScript. Cosas como setTimeout, los HTTP Request o el DOM son funciones agregadas por el navegador, y por eso estas se ejecutan en una pila de llamadas distintas.
Saludos Joel y espero haber respondido tu pregunta :D
Sincronia: significa que cada una de las tareas que se ejecutan en el CallStack deben completarse para poder continuar con la siguiente y mientras no suceda el programa no permitira ejecutar nuevas tareas.
Asincronia: significa que puedo ejecutar una tarea y luego otra sin necesidad de esperar a que termine la primera y a medida que las tareas vallan terminando vamos recibiendo los resultados, los cuales no necesariamente llegaran en el mismo orden de ejecucion.
Eso es lo que no entiendo, busca en Google la definicion de sincronismo y asincronismo. Sincronismo es que ocurran dos o mas hechos a la vez, Asincronismo es solo uno a la vez... Porque se usan los conceptos al reves?
Las tareas se apilan de abajo hacia arriba
en la parte inferior de la pila esta el objeto global
alli se empiezan a llamar las tareas.
Cuando una tarea es llamada por una funcion, esta se pone en la cima de la pila
JavaScript trabaja una tarea a la vez.
Tengo que intentar usar más el debugger y menos los console.log para debugear jeje, gran explicación y útil la herramienta para ver el Call Stack.
Call Stack(Pila de ejecucion) y Memory Heap
JavaScript tiene un solo subproceso con un contexto de ejecución global, esto significa que JavaScript maneja una sola pila de llamadas(Call Stack) y un Memory Heap, que hace referencia a la parte de la memoria no estructurada donde se guardan los objetos y funciones. Las funciones del Call Stack se procesarán en el orden en que se llama, comúnmente conocido como Last-In, First-Out (LIFO).
El motor de JavaScript utiliza una pila de llamadas(Call Stack) para administrar los contextos de ejecución: el contexto de ejecución global y los contextos de ejecución de funciones. La pila de llamadas funciona según el principio LIFO, es decir, el último en entrar es el primero en salir.
Cuando ejecuta un script, el motor JavaScript crea un contexto de ejecución global(En la base de la pila reposa el Global Object) lo coloca en la parte superior de la pila de llamadas(Call Stack).
Siempre que se llama a una función, el motor de JavaScript crea un contexto de ejecución de función para la función, lo coloca en la parte superior de la pila de llamadas(Call Stack) y comienza a ejecutar la función.
Si una función llama a otra función, el motor de JavaScript crea un nuevo contexto de ejecución de función para la función que se está llamando y lo coloca en la parte superior de la pila de llamadas(Call Stack).
Cuando se completa la función actual, el motor de JavaScript la saca de la pila de llamadas(Call Stack) y reanuda la ejecución donde la dejó en la última lista de código.
El script se detendrá cuando la pila de llamadas esté vacía.
Ejemplo de pila de llamadas(Call Stack) de JavaScript
functionadd(a, b){return a + b;}functionaverage(a, b){returnadd(a, b)/2;}// debugger;// Si hacemos el debugger con Chrome al ejecutarlo nuestro Script// en la pila de llamadas(Call Stack), se crea anonymous que es// el objeto globalaverage(10,20);
En la base de la pila reposa el Global Object, que este es el objeto que nos da el navegador, cuando se ejecuta el script, el motor de JavaScript coloca el contexto de ejecución global (indicado por main() o global() función en la pila de llamadas(Call Stack).
El contexto de ejecución global entra en la fase de creación y pasa a la fase de ejecución.
El motor de JavaScript ejecuta la llamada a la average(10, 20) función y crea un contexto de ejecución de función para la average() función y lo coloca en la parte superior de la pila de llamadas(Call Stack):
El motor de JavaScript comienza a ejecutar el average() ya que está en la parte superior de la pila de llamadas.
La average() función llama a la add() función. En este punto, el motor de JavaScript crea otro contexto de ejecución de función para la add() función y lo coloca en la parte superior de la pila de llamadas(Call Stack):
El motor de JavaScript ejecuta la add() función y la saca de la pila de llamadas(Call Stack):
En este punto, la average() función está en la parte superior de la pila de llamadas, el motor JavaScript la ejecuta y la saca de la pila de llamadas(Call Stack).
Ahora, la pila de llamadas(Call Stack) está vacía, por lo que el script deja de ejecutarse:
Desbordamiento de pila
La pila de llamadas tiene un tamaño fijo, dependiendo de la implementación del entorno de host, ya sea el navegador web o Node.js.
Si el número de contextos de ejecución supera el tamaño de la pila, se producirá un desbordamiento de la pila.
Por ejemplo, cuando ejecuta una función recursiva que no tiene condición de salida, resultará en un error de desbordamiento de pila: