"No bloquees el bucle de eventos..." - probablemente hayas oído esta frase muchas veces... No me sorprende porque es una de las premisas más importantes cuando se trabaja con Node. Pero también hay una segunda "cosa" que deberías abstenerte de bloquear - el Worker Pool. Si se descuida, puede tener un impacto significativo en el rendimiento de la aplicación e incluso en su seguridad.
Hilos
Lo principal a recordar: hay dos tipos de hilos en Node.js: Main Thread - que es manejado por Bucle de eventosy Pool de trabajadores (pool de hilos) - que es el pool de hilos -
gracias a libuv. Cada uno de ellos tiene un trabajo diferente. El objetivo del primero es gestionar las operaciones de E/S no bloqueantes, y el segundo es responsable del trabajo intensivo de la CPU y también de las E/S bloqueantes.

But what is a thread and how it’s different than a process? There are several differences, but the most important one for us is how the memory is allocated to them. You can think about a process like about an application. Inside each process, there is a chunk of memory dedicated just for this process. So, one process doesn`t have access to the memory of the second one, and this property ensures high security. To establish communication between them, we must do some work. Threads are different. Threads runs inside a process and share the same memory so there is no problem at all with threads sharing data.
Sin embargo, hay una cuestión que causa problemas. Se llama condición de carrera. Los hilos pueden ejecutarse al mismo tiempo, así que ¿cómo sabemos cuál termina primero? Puede ocurrir que la primera vez que lo ejecutes, la primera operación termine primero, y la próxima vez puede resultar lo contrario y la segunda operación termine antes que la primera. ¡Imagínate trabajar con operaciones de escritura/lectura en esas condiciones! ¡Una pesadilla! A veces es muy difícil escribir correctamente código en un entorno multihilo.
Además, los lenguajes multihilo tienen una gran sobrecarga de memoria porque crean un hilo distinto para cada petición; así, si quieres llamar a 1000 peticiones, crean 1000 hilos.
¿Cómo solucionar este problema? Utilizando un único hilo. Y eso es lo que Nodo te ofrece.

Como JavaScript desarrollador Le animo a que vea el película
en la que Bart Belder explica claramente el concepto de bucle de eventos. El diagrama anterior está tomado de su presentación. Y si no conoce estos términos en absoluto, tanto Nodo y Libuv tienen una documentación excelente 🙂 .
Acerca del bloqueo
En JavaScript desarrollo industria dicen que porque Nodo es monohilo y no bloqueante, se puede lograr una mayor concurrencia con los mismos recursos que con las soluciones multihilo. Es cierto, pero no es tan bonito y fácil como parece.
Desde Node.js es single-threaded (parte JS), las tareas intensivas de CPU bloquearán todas las peticiones en curso hasta que se complete la tarea en particular. Por lo tanto, es cierto que en Node.js puedes bloquear todas las peticiones sólo porque una de ellas contenía una instrucción de bloqueo. El código bloqueante significa que tarda más de unos milisegundos en terminar. Pero no confunda un tiempo de respuesta largo con bloqueo. La respuesta de la base de datos puede tomar mucho tiempo, pero no bloquea su proceso (aplicación).
Los métodos bloqueantes se ejecutan de forma sincrónica y los no bloqueantes de forma asincrónica.
¿Cómo puedes ralentizar (o bloquear) tu bucle de eventos?
- regex vulnerable - una expresión regular vulnerable es aquella en la que su motor de expresiones regulares puede tardar un tiempo exponencial; puede leer más sobre ellas aquí,
- Operaciones JSON en objetos grandes,
- utilizando las API síncronas de Nodo en lugar de versiones asíncronas; todos los métodos de E/S de la biblioteca estándar Node.js ofrecen también sus versiones asíncronas,
- otros errores de programación, como los bucles infinitos síncronos.
En ese caso, dado que el Worker Pool utiliza un pool de hilos, ¿es posible bloquearlos también? Lamentablemente, sí 🙁 . Nodo se basa en una filosofía un hilo para muchos clientes. Supongamos que una determinada tarea realizada por un Worker específico es muy compleja y necesita más tiempo para ser terminada. Como resultado, el Worker se bloquea y no puede ser utilizado para ejecutar ninguna de las otras tareas pendientes hasta que sus instrucciones sean ejecutadas. Como probablemente ya habrás adivinado, esto puede afectar al rendimiento. Puedes prevenir estos problemas minimizando la variación en los tiempos de las Tareas mediante el uso de la partición de Tareas.
Conclusión
Evita el bloqueo, eso seguro. Si sólo puedes, elige siempre versiones asíncronas de las API de la biblioteca estándar. De lo contrario, después de ejecutar su aplicación, el cliente puede experimentar varios problemas, empezando por el rendimiento degradado y terminando en la retirada completa, que es fatal desde la perspectiva del usuario.
Más información:
Por qué debería (probablemente) utilizar Typescript
¿Cómo no matar un proyecto con malas prácticas de codificación?
Estrategias de obtención de datos en NextJS