Skip to content

undefinedschool/notes-event-loop

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

30 Commits
 
 
 
 

Repository files navigation

Funciones First-Class

Contenido


Intro

JavaScript es un lenguaje de programación single-thread, lo que equivale a decir que sólo puede hacer 1 cosa a la vez, ejecutar 1 sola instrucción y finalizarla antes de pasar a la siguiente.

Tener 1 sólo thread de ejecución significa tener también 1 sólo stack, por lo que las operaciones lentas (como el procesamiento de imágenes o los requests HTTP) resultan bloqueantes (bloquean el thread de ejecución), en el sentido de que el resto de las instrucciones de nuestro código no se ejecutarán hasta que estas finalicen.

Nota: llamamos operaciones bloqueantes (o blocking) a aquellas que son lentas, de las que no podemos obtener un resultado de forma inmediata

Si tenemos muchas operaciones bloqueantes, vemos claramente el gran impacto que esto tendría en la performance de nuestra aplicación. Un browser por ejemplo, no podría realizar ciertas operaciones como renderizar la UI correspondiente, resultando en una experiencia de uso poco deseable.

What the heck is the event loop anyway? | Philip Roberts | JSConf EU

Ver What the heck is the event loop anyway? | Philip Roberts | JSConf EU

👉 La forma que tenemos de evitar bloquear nuestra aplicación es escribiendo código asincrónico, utilizando callbacks o Promises.

↑ Ir al inicio

Concurrencia y el Event Loop

Como mencionamos antes, JavaScript es single-thread, por lo que no puede ejecutar más de 1 tarea (proceso) a la vez. Esto es cierto, pero la plataforma (o entorno) sobre la que corremos JavaScript si permite realizar más tareas, de forma concurrente. Por ejemplo, a través del browser tenemos acceso a las Web APIs, que nos proveen de más threads para realizar ciertas tareas en un 2do plano, es decir, fuera del thread principal. Algo similar ocurre en Node.

JavaScript & the Event Loop

👉 Cuando estas APIs externas terminan de realizar la tarea asignada, la envían a una cola de tareas (callback queue). Es en este momento cuando aparece el event loop para realizar una tarea muy simple: encargarse de chequear el stack de funciones actual y el callback queue; si el stack se encuentra vacío, toma el primer callback1 (del callback queue) y lo pushea al stack para que sea ejecutado.

Las tareas asincrónicas se delegan a APIs externas (threads adicionales) y luego son encoladas (en el callback queue) para eventualmente ejecutarse en el thread principal.

👉 Es importante notar que el Event Loop no forma parte de JavaScript en si, sino del entorno donde este se ejecute (browser, Node, etc).

↑ Ir al inicio

Event Loop

El concepto de Event Loop resulta entonces, bastante simple. Se trata de un loop infinito que espera a que el thread principal esté libre y haya tareas disponibles esperando, para asignarle una nueva tarea, proveniente del callback queue, para luego quedarse esperando hasta que haya más tareas.

↑ Ir al inicio

Event Loop y rendering

El rendering en el browser nunca sucede mientras el runtime de JavaScript (engine) se encuentra ejecutando una tarea, independientemente de si una tarea toma o no mucho tiempo. Los cambios que realicemos en el DOM no se verán reflejados hasta que la tarea finalice.

Por lo tanto si una tarea toma mucho tiempo, estamos bloqueando la UI (y el thread) y el browser no puede ocpuarse de otras cosas (como procesar eventos). Luego de cierto tiempo, dependiendo de cada browser, mostrará un mensaje indicando que la página no responde, por lo que necesitaremos cerrar la pestaña, el browser o terminar de alguna forma el proceso.

👉 Es por esto que debemos evitar realizar tareas muy complejas (computacionalmente costosas) en el thread principal (o que tomen mucho tiempo) si queremos evitar una mala UX.

↑ Ir al inicio

Paso a paso

👉 Ver ✨♻️ JavaScript Visualized: Event Loop

↑ Ir al inicio

macrotasks & microtasks

A su vez, las tareas asincrónicas pueden dividirse en macro y micro tareas:

  • macrotasks: como SetInterval o SetTimeout, se ejecutan en el siguiente event loop, es decir, la próxima iteración.
  • microtasks: como una Promise resuelta, se ejecutan antes del inicio del próximo event loop, es decir, tienen prioridad sobre las macrotasks y se van a ejecutar antes. Los mismo sucede con Async/Await, al tratarse de otra forma de escribir Promises.

Podríamos decir entonces, que en realidad el callback queue está compuesto por 2 colas más pequeñas: microtask queue y macrotask queue y que el Event Loop se va a encargar de asignar al thread principal, primero todas las microtasks y a continuación, cuando todas estas se completen, las macrotasks.

👉 Inmediatamente después de cada macrotarea, el engine ejecuta todas las tareas de la cola de microtareas, antes de cualquier otra macrotask, rendering, etc. Las microtasks siempre tienen prioridad sobre el resto de las tareas asincrónicas.

↑ Ir al inicio

Event Loop y async/await

The Async Await Episode I Promised

Ver The Async Await Episode I Promised

↑ Ir al inicio

Tips

↑ Ir al inicio

Web Workers

Para realizar cálculos complejos u operaciones muy largas y evitar bloquear el event loop, lo más conveniente es utilizar Web Workers.

Básicamente, nos permiten ejecutar código en otro thread, fuera del principal.

👉 Web Workers pueden intercambiar información con el thread principal, pero tienen sus propias variables e incluso su propio event loop.

Los Web Workers no tienen acceso al DOM, por lo que suelen utilizarase para realizar cálculos complejos y aprovechar los múltiples cores del CPU para poder ejecutar código de forma paralela, a diferencia de la concurrencia que nos provee el asincronismo.

↑ Ir al inicio


1Hay tareas del callback queue que tienen prioridad sobre otras y por lo tanto el event loop las moverá antes al thread principal. Ver macrotasks & microtasks.

Releases

No releases published

Packages

No packages published