Para entender cómo se maneja la ejecución del código JavaScript, es crucial comprender los componentes clave de su motor de ejecución en los navegadores: el Memory Heap y el Call Stack.
¿Qué es el Memory Heap?
El Memory Heap es el espacio donde se almacenan variables, funciones y objetos creados en JavaScript de forma aleatoria. Actúa como un almacén desorganizado donde el navegador gestiona la memoria de manera eficiente, permitiendo que las aplicaciones JavaScript funcionen sin problemas.
¿Cómo opera el Call Stack?
El Call Stack es una pila de tareas donde se registran las funciones que deben ejecutarse. Cuando se llama a una función, esta se agrega al Call Stack, ejecutándose de manera secuencial. Por ejemplo, si tienes una función holaMundo que llama a otra función miNombreEsDiego, el Call Stack ejecutará primero holaMundo y luego miNombreEsDiego, de forma simple y secuencial.
¿Qué es la programación síncrona en JavaScript?
En un entorno síncrono, JavaScript ejecuta una tarea a la vez en el Call Stack. Este enfoque puede llegar al temido Stack Overflow, una situación en la que el Call Stack se llena más allá de su capacidad y el navegador puede bloquearse. Para solventar este problema, el navegador debe cerrarse y abrirse nuevamente.
JavaScript, por naturaleza, funciona de forma síncrona, ejecutando cada línea de código en orden. Sin embargo, ciertos mecanismos permiten que JavaScript también pueda manejar tareas asincrónicamente.
¿Cómo se realiza la programación asíncrona?
¿Qué son las Web APIs?
Las Web APIs son herramientas que permiten que JavaScript ejecute tareas de manera asíncrona, proporcionando simultaneidad. Cuando una función de Web API se llama, se transfiere a la sección de las Web APIs y se ejecuta en paralelo al Call Stack. Una vez completada, la tarea se mueve al Queue.
¿Qué es el Event Loop?
El Event Loop interroga constantemente al Call Stack para verificar si está vacío. Cuando lo está, extrae una tarea del Queue y la transfiere al Call Stack para ejecutar. De este modo, tareas asincrónicas se integran ordenadamente en el flujo de ejecución.
Ejemplo de setTimeout en programación asíncrona
Considera un caso donde se utiliza setTimeout, una función que actúa asincrónicamente:
Una vez que el Call Stack está vacío, el event loop mueve el console de 2 del Queue al Call Stack.
El resultado en consola sería: 1, 3 y 2. Aunque setTimeout parece ser instantáneo, su resultado aparece solo cuando el Stack está vacío.
¿Qué son las promesas en JavaScript?
Las promesas en JavaScript, al igual que las funciones de Web API, facilitan la programación asíncrona. Permiten que funciones específicas se ejecuten en paralelo al flujo principal, mejorando la eficiencia y evitando cuellos de botella en aplicaciones de alto rendimiento.
¿Cuál es el uso de async/await?
async y await son sintaxis modernas para manejar promesas, haciendo que el código asíncrono se vea y se lea como si fuera síncrono. Proporcionan una forma más clara y manejable de estructurar código asincrónico, especialmente en operaciones complejas o jerárquicas.
Con esta comprensión, puedes mejorar la forma en que escribes y gestionas tu código JavaScript, maximizando sus capacidades síncronas y asíncronas. ¡Adelante, sigue explorando y dominando el mundo del desarrollo con JavaScript!
El JavaScript Engine ejecuta el código desde la Call Stack (pila de llamadas).
Cuando una operación asíncrona se encuentra (como una solicitud de red), se envía al Web APIs del navegador o a Node APIs en Node.js.
Una vez que la operación asíncrona se completa, su callback se envía a la Task Queue (cola de tareas).
El Event Loop verifica la Call Stack y, si está vacía, mueve el callback de la Task Queue a la Call Stack para su ejecución.
No entendía cómo es que esto funcionaba con Node y con tu comentario me quedó claro. Muchas gracias compa 👍🏻
Me tomó 9 horas en saber.
Para poder entender lo que es programación síncrona y asíncrona en JavaScript, primero vamos a hablar de cómo funciona JavaScript Engine en el navegador.
Conceptos que debes de tener en cuenta:
Memory heap: Es el espacio en donde se van a guardar todas las variables, todas las funciones y objetos que creamos o construimos en JavaScript, y se van a estar guardando en el memory heap de forma aleatoria.
Call Stack: Es la pila donde se van a empezar a llamar cada una de las funciones que tenemos que ejecutar en nuestro programa. Por ejemplo, yo tengo esta función console.log("Hola Mundo"), y esa función manda a llamar esta otra función console.log("Mi nombre es Diego"). Este Call Stack lo que va a hacer es mandar a llamar la primera función, ejecuta "Hola Mundo", y se manda a llamar la segunda función, ejecuta "Mi nombre es Diego".
A esta función se le conoce como programación síncrona. Quiere decir que se está trabajando una tarea a la vez. JavaScript funciona trabajando una tarea a la vez, y eso va a estar funcionando prácticamente en el Call Stack.
Stack Overflow
No, no es esa página famosa entre los desarrolladores. Se refiere a cuando llevamos nuestro stack de tareas a un punto en donde excede el número o la memoria que tiene permitida para poder ejecutar las tareas.
Lo que sucede con esto es que prácticamente nuestro navegador deja de funcionar, crashea. Tenemos que cerrarlo, abrirlo, para que vuelva a liberar la memoria que tenía en este stack y pueda funcionar de la forma en la que nosotros esperamos.
Prgramación Asíncrona
JavaScript por defecto solo funciona de forma síncrona. Pero sí tenemos forma de poder hacer que JavaScript pueda empezar a trabajar ciertas tareas de forma asíncrona, que quiere decir en simultáneo.
Pero antes de hacerlo, debes de entender bien cómo funciona un poco más el tema del navegador con ciertos factores muy importantes.
Lo primero que tenemos es el Call Stack.
Lo segundo que tenemos la parte de las Web APIs. Las Web APIs es lo que va a hacer que JavaScript pueda funcionar o se comporte de manera asíncrona. Al momento de que nosotros tenemos una función que es una Web API, lo que hace es que la va a mandar a la sección de Web API y va a hacer que se ejecute en simultáneo mientras que el Call Stack sigue sacando las funciones que tiene ahí.
La Web API lo que va a hacer es que se va resolver en ese momento, ya que termine de resolverse, lo que tenga que hacer en la función, lo va a bajar al Queue, que es prácticamente una sala de espera.
Y ya por último, el Event loop va a estar verificando que el Call Stack esté vacío. Si el Call Stack ya está vacío, va a tomar lo que existe en el Queue y lo va a regresar al Call Stack para que se pueda terminar de ejecutar. Si no está vacío, va a mantener lo que está en el Queue en espera hasta que se logre liberar el Call Stack y en ese momento le va a dar paso para que la función que se tiene que terminar de ejecutar pueda pasar al Call Stack y en ese momento se termine de ejecutar todo nuestro programa.
Esta es la forma en la cual nosotros trabajamos código en JavaScript de forma síncrona y de forma asíncrona, utilizando por ejemplo Web APIs, que hace que nuestro código pueda comportarse como código asíncrono. Y para esto vamos a utilizar lo que se llaman promesas. Promesas que también pueden ser Async and Await, que van a hacer que nuestro código pueda tener este comportamiento de asíncrono para que se ejecute en paralelo.
Excelente aporte
Función del Motor de JavaScript
El flujo de pasos ordenado de cómo un motor de JavaScript (como V8) procesa y ejecuta código JavaScript, detallando los componentes que intervienen en cada etapa:
1. Recepción del Código JavaScript
Componente: Motor de JavaScript
Descripción: El motor de JavaScript recibe el código fuente para ser procesado.
2. Parsing (Análisis Sintáctico)
Componente: Parser
Descripción:
El Lexer convierte el código fuente en tokens (elementos léxicos como palabras clave, operadores, etc.).
Luego, el Parser toma estos tokens y construye un Abstract Syntax Tree (AST), que es una representación estructurada del código.
3. Optimización Inicial
Componente: Interpreter
Descripción: El AST se convierte en bytecode (un código intermedio) por el intérprete. En motores modernos como V8, este bytecode se puede ejecutar directamente o servir como base para la optimización.
4. Gestión de la Memoria
Componente: Memory Heap y Garbage Collector (GC)
Descripción:
El Memory Heap es donde se almacenan los objetos y variables.
El Garbage Collector gestiona la memoria, limpiando objetos no utilizados para liberar espacio.
5. Ejecución del Código
Componente: Execution Engine
Descripción:
Interpreter: Ejecuta el bytecode línea por línea.
JIT Compiler (Just-In-Time): Identifica funciones que se ejecutan frecuentemente y las compila en código máquina para mejorar el rendimiento.
Durante la ejecución, el motor utiliza la Call Stack para rastrear las funciones en ejecución y la Memory Heap para almacenar los datos.
El Event Loop supervisa el Call Stack y la Task Queue.
Las tareas asíncronas como setTimeout o promesas se encolan en la Task Queue o Microtask Queue.
Cuando el Call Stack está vacío, el Event Loop ejecuta las tareas en las colas.
7. Interacción con APIs Externas
Componente: Web APIs, FFI (Foreign Function Interface)
Descripción:
Las Web APIs proporcionan funcionalidades adicionales como DOM, Fetch, Timers, etc., que no forman parte del núcleo de JavaScript.
El FFI permite que JavaScript interactúe con código escrito en otros lenguajes (como C++ en Node.js).
8. Optimización Dinámica
Componente: JIT Compiler y Execution Engine
Descripción:
Durante la ejecución, el JIT Compiler sigue optimizando el código, convirtiendo las partes más utilizadas en código máquina altamente optimizado.
El Execution Engine se encarga de ejecutar este código optimizado.
9. Liberación de Recursos
Componente: Garbage Collector (GC)
Descripción: Después de que el código ha terminado de ejecutarse, el Garbage Collector se encarga de liberar los recursos y la memoria ocupada por los objetos y variables que ya no se usan de la memoria heap.
10. Finalización de la Ejecución
Componente: Motor de JavaScript
Descripción: El motor finaliza la ejecución del código, habiendo gestionado las tareas, optimizado el rendimiento, y limpiado la memoria.
Esto es nuevo
Si justo seguía la ruta de JavaScript y me aparece que no complete el primer curso de la ruta jaja
Igual... incluso han borrado el curso practico de JS, justo lo estaba siguiendo.
Que bueno que metieron este tema, en el otro curso no me quedó tan claro y hasta se me hizo inentendible con el otro profe, espero entenderlo mejor con Diego, eso si por favor hagan algun curso práctico de JS mejorado con ejemplos reales y bien piolas.
Gracias!!!!
Me parece que la animación del video se podría mejorar y hacerlo más intuitivo, de esta forma nos quedaría muchísimo más claro el ejemplo.
ya veo... no entendi nada.
Me costó entender esta clase, tuve que verla 3 veces; pero ya estoy listo para continuar el curso. Ánimo a todo la familia Platzi ¡A seguir aprendiendo!. Un fuerte abrazo.
En programación, los conceptos de sincronía y asincronía se refieren a la forma en que se manejan las tareas y la comunicación entre diferentes partes de un programa.
Síncrono
En un proceso sincrono, las tareas se ejecutan secuencialmente. Esto significa que cada tarea debe completarse antes de que la siguiente pueda comenzar. La ejecución se bloquea hasta que la tarea actual se complete, lo que puede llevar a tiempos de espera si una tarea es lenta o implica operaciones que consumen mucho tiempo, como leer un archivo o hacer una solicitud de red.
Asincrono
En un proceso asincrono, las tareas pueden iniciarse y ejecutarse de manera no secuencial. Esto permite que otras tareas continúen ejecutándose mientras se espera la finalización de una tarea más lenta, mejorando la eficiencia y la capacidad de respuesta del programa. En JavaScript, esto se maneja comúnmente mediante callbacks, promesas y async/await.
En pocas palabras para que. javascript pueda ser asincrono las funciones se las dividen entre el JS engine compuesto por el call stack y la memoria heap que se encarga del codigo javascript funciones, variables primitivas, referencias de memoria deobjetos, etc y esta el otro ayudante que es el web api donde todas laspeticiones APIS de javascript como el DOM, settime, geolocalizacion, fetch API, etc se resuelven ahi es por eso que se pueden resolver codigo en paralelo, cuando el web api termina el even loop jala esa callback y lo mete en el callback queue que es la sala de espera, cuando llega su turno se mete al call stack y su respuesta se procesa para ser representada al usuario, como resumen el Jaca script engine y el web API ptrabajan en paralelo cuando se necesita ara crear asincronismo.
Mis notas:
Aquí comienza mi verdadero miedo a javaScript jaja
Naturaleza de un solo hilo:* JavaScript es de un solo hilo (single-threaded), procesando una tarea a la vez.
Stack Overflow:* Ocurre cuando el Call Stack se llena, típicamente por recursión excesiva.
Funciones asíncronas:* Ayudan a evitar bloqueos y mejoran la eficiencia.
Web API:* Proporciona funcionalidades adicionales como setTimeout, fetch, DOM APIs.
Maneja operaciones asíncronas fuera del hilo principal de JavaScript.
Callback Queue (Task Queue):* Almacena callbacks de operaciones asíncronas completadas.
Event Loop:* Verifica constantemente si el Call Stack está vacío.
Mueve tareas del Callback Queue al Call Stack cuando está libre.
Las computadoras no entienden JavaScript de forma nativa; ellas solo hablan "binario" (ceros y unos). El motor actúa como un traductor de alta velocidad que convierte el texto que tú escribes en instrucciones que el procesador de tu computadora puede entender.
Los motores más famosos
Cada navegador tiene su propio "sabor" de motor, aunque todos siguen los mismos estándares (ECMAScript):
V8: Creado por Google. Es el más famoso y potente. Vive en Chrome, Edge y también es el corazón de Node.js.
SpiderMonkey: El primer motor de la historia, creado para Netscape y que hoy impulsa a Firefox.
JavaScriptCore: El motor de Apple para Safari.
Resumen crítico sobre asincronía y multihilo en JavaScript:
JavaScript es un lenguaje single-threaded, lo que significa que ejecuta código en un único hilo principal.
Para evitar que tareas lentas (como operaciones I/O o timers) bloqueen la ejecución y congelen la interfaz o el flujo del programa, JavaScript implementa un modelo de programación asincrónica basado en el event loop.
El event loop permite delegar tareas asincrónicas a APIs externas (Web APIs en navegador o APIs del sistema en Node.js) que corren en hilos separados. Cuando estas tareas terminan, sus callbacks se encolan para ser procesados uno a uno en el hilo principal, manteniendo la fluidez y capacidad de respuesta sin usar multihilo real dentro del motor JavaScript.
La asincronía en JavaScript se originó en los navegadores para manejar eventos y comunicación sin bloquear la interfaz, y luego fue adoptada y extendida por Node.js para servidores. Esta programación asincrónica es crucial porque compensa la limitación de un solo hilo, permitiendo realizar múltiples tareas concurrentes sin bloquear.
Aunque JavaScript no tiene multihilo nativo en el hilo principal, se pueden usar Web Workers o Worker Threads para procesamiento paralelo real cuando es necesario.
En resumen, JavaScript logra una eficiencia parecida al multihilo mediante el event loop y la asincronía, simplificando el desarrollo al evitar la complejidad de la sincronización de hilos tradicionales, y garantizando una experiencia fluida en la web y servidores.
-----------------------------------------
Ejemplo Síncrono (bloqueante):
console.log("Inicio");
function tareaLarga() {
const start = Date.now();
while (Date.now() - start < 3000) {
// simula tarea pesada bloqueante
}
}
tareaLarga();
console.log("Fin - Esta línea se ejecuta después de tareaLarga");
-----------------------------------------
Ejemplo Asíncrono (no bloqueante):
console.log("Inicio");
setTimeout(() => {
console.log("Tarea larga terminada");
}, 3000);
console.log("Fin - Esta línea se ejecuta inmediatamente");
-----------------------------------------
Importancia de la asincronía:
- Permite que el hilo principal no se bloquee con tareas lentas (como I/O o timers).
- Mantiene la interfaz o el programa responsivo.
- Permite manejar múltiples operaciones concurrentes eficientemente.
- Es fundamental en JavaScript para compensar su modelo single-threaded y brindar una experiencia fluida y escalable.
Resumen gráfico de esta clase.
Entendí que las funciones WebAPI son procesadas en simultaneo y luego se envian a un Queue o fila, y el evenloop como un trafico espera que el call stack este vacio para pasarle trabajo de la fila (Queue)
En JavaScript, el manejo de operaciones asíncronas es más complejo de lo que parece inicialmente. Aunque comúnmente se asocia la asincronía con las Web APIs del navegador, en realidad las tareas asíncronas pueden provenir de múltiples fuentes: del propio motor de JavaScript, del navegador, o del entorno de ejecución (como Node.js). El sistema utiliza diferentes colas para gestionar estas tareas: una para operaciones más grandes (macrotareas) como temporizadores o eventos de usuario, y otra para operaciones más pequeñas y prioritarias (microtareas) como las Promesas. El Event Loop, que es el mecanismo central de este sistema, constantemente supervisa estas colas y el Call Stack (donde se ejecuta el código actual). Cuando el Call Stack se vacía, el Event Loop primero procesa todas las microtareas pendientes, luego toma una macrotarea para procesarla, y repite este ciclo. Este sistema permite que JavaScript, siendo un lenguaje de un solo hilo de ejecución, pueda manejar múltiples operaciones simultáneamente sin bloquearse, lo cual es esencial para crear aplicaciones web responsivas y eficientes. Entender este funcionamiento es fundamental para cualquier desarrollador que trabaje con JavaScript, ya que afecta directamente cómo se comportará nuestro código asíncrono.
Entendí el concepto pero no entendí el ejemplo
Muy buena explicacion ese es un tema de JS que nunca entendi del todo hasta ahora