Cómo un solo hilo ejecuta código "concurrente"
Usa ← → para navegar · Espacio = siguiente paso · R = reiniciar
Es el programa que lee y ejecuta tu código. Solo sabe ejecutar JS: no sabe nada de setTimeout, el DOM o la red. Eso lo provee el entorno (navegador o Node).
El motor tiene un único Call Stack: solo puede ejecutar una función a la vez, de forma sincrónica. No hay dos líneas de tu JS corriendo en paralelo.
Cada vez que se llama a una función se apila un "frame"; cuando termina, se desapila. Si el stack nunca se vacía (loop infinito, recursión sin fin), el hilo se congela.
Es el "todo": motor JS + Web APIs (o APIs de Node) + colas de callbacks + Event Loop. El navegador es un runtime; Node.js es otro runtime (con libuv en vez de las Web APIs del browser).
Síncrono: cada línea espera a que termine la anterior. Asíncrono: se dispara una operación (timer, red, archivo) y el resultado llega después, sin bloquear el hilo mientras se espera.
Una función que se pasa como argumento para ejecutarse más adelante, cuando algo termine (setTimeout(fn, 1000), btn.addEventListener('click', fn)). La forma más primitiva de manejar asincronía en JS.
Anidar callbacks dentro de callbacks para encadenar pasos asíncronos vuelve el código difícil de leer y mantener. Las promesas nacieron para resolver este problema.
Un objeto que representa un valor que todavía no existe pero existirá (o fallará) en el futuro. 3 estados: pending, fulfilled y rejected. Se consume con .then() / .catch() o con await.
Azúcar sintáctica sobre promesas. Una función async siempre devuelve una promesa; await pausa esa función (sin bloquear el hilo) hasta que la promesa se resuelve, y el código se lee como si fuera sincrónico.
El mecanismo que coordina todo: mientras el Call Stack esté vacío, va tomando callbacks pendientes (timers, promesas, eventos de UI, I/O) y los ejecuta uno por uno. Permite que un lenguaje de un solo hilo maneje miles de operaciones "al mismo tiempo".
setTimeout, fetch, requestAnimationFrame y los listeners NO los maneja el motor JS: viven en las Web APIs del navegador (C++/OS). Trabajan en paralelo y, al terminar, depositan su callback en la cola correspondiente.
requestAnimationFrame (puede saltearse, ~60fps)
click, input…) y los timers (setTimeout, setInterval) son ambos macrotasks; el navegador los maneja como task sources distintas. Se consume una por vuelta.
Promise.then, queueMicrotask, MutationObserver. Se drena completa después de CADA macrotask, antes del render.
setTimeout en cambio se difiere a una vuelta posterior.
await pausa la función y libera el hilo; lo que sigue se reanuda como una microtarea cuando la promesa resuelve. No bloquea: por eso el spinner se puede pintar mientras se espera la red.
innerHTML, appendChild modifican el DOM al instante en el Call Stack. Lo que se difiere al render es el recálculo de estilo/layout y el repintado.
/health cada 10s) encola su callback en la Task Queue cada intervalo. Entre chequeos el hilo queda libre; el timer y la red trabajan en las Web APIs sin bloquear.