Todos sabemos que NodeJS es de subproceso único, lo que significa que si tenemos una operación asíncrona/espera en nuestro código, el nodo esperará a que se realice antes de ejecutar el resto del código. Entonces, si un usuario realiza una solicitud asíncrona, ¿otros usuarios deberían esperar a que se realice antes de realizar solicitudes también?
Aquí creé un ejemplo simple, la primera ruta usa una función asíncrona y tarda 10 segundos antes de enviar una respuesta y la segunda ruta envía una respuesta inmediatamente.
Cuando envié una solicitud a la primera ruta y mientras esperaba una respuesta, envié otra solicitud a la segunda ruta y obtuve una respuesta a pesar de que la primera ruta aún no terminó de ejecutar el código.
¿Por qué no bloquea en este ejemplo?
function sleep(){ return new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve(true) },10000) }).then(val=>val) } router.get('/route1',async (req,res)=>{ const test = await sleep() res.send('HELLO WORLD') }) router.get('/route2',(req,res)=>{ res.send("HELLO WORLD") })await solo bloquea/suspende la ejecución de la función actual, no todo el intérprete. De hecho, en el momento en que una función alcanza la primera await dentro de la función, la función devuelve inmediatamente una promesa y otros procesos después de que esa función (u otros eventos que ocurran) se ejecuten libremente.
Entonces, en su ejemplo, cuando golpea await sleep() , la ejecución de esa función se suspende hasta await se resuelva/rechace y la función async contenedora devuelve inmediatamente una promesa incumplida. Dado que Express con router.get() no está haciendo nada con esa promesa devuelta, simplemente la ignora y devuelve el control al bucle de eventos. Algún tiempo después, su segunda solicitud llega al servidor, se coloca un evento en la cola de eventos de nodejs y se llama a Express con ese evento y sirve a su segundo controlador de ruta.
Entonces, si un usuario realiza una solicitud asíncrona, ¿otros usuarios deberían esperar a que se realice antes de realizar solicitudes también?
No. Solo se suspende la instancia de ese controlador de solicitud que contiene la await . Todavía pueden ocurrir otras ejecuciones en el intérprete y otro controlador de eventos a través del bucle de eventos (como otras solicitudes entrantes), por lo que aún se pueden procesar otras solicitudes, aunque un controlador de solicitudes esté await . Esto ilustra cómo await no bloquea ni suspende todo el intérprete, solo la ejecución de una función.
Cuando envié una solicitud a la primera ruta y mientras esperaba una respuesta, envié otra solicitud a la segunda ruta y obtuve una respuesta a pesar de que la primera ruta aún no terminó de ejecutar el código. ¿Por qué no bloquea en este ejemplo?
Solo la primera ruta fue suspendida por la await . Otros eventos y otras solicitudes entrantes aún se pueden procesar sin problemas.
NodeJs no es de subproceso único . Puedes comprobarlo con estos pasos:
Crea un archivo js y luego ejecútalo:
while(true)
En la terminal, ejecuta este comando para obtener la cantidad de subprocesos que se utilizan para ejecutar este archivo js.
NÚM= ps M <pid> | wc -l && número de eco del hilo es: $((NUM-1))
Y puedes ver que while(true) usa más de 1 hilo.
Volvamos a su código. La razón por la que puede obtener el resultado de la solicitud a /route2 inmediatamente cuando su solicitud a /route1 aún no ha terminado porque NodeJs usa EventLoop para hacer que las funciones asincrónicas no bloqueen el hilo principal. Cuando llama a la función de suspensión, NodeJs iniciará un temporizador y luego sacará su devolución de llamada de la pila de llamadas (es por eso que la solicitud a /route2 no está bloqueada por /route1 ), y cuando su temporizador está fuera de la resolve(true) lo hará se colocará en EventQueue y, con la ayuda de EventLoop, se ejecutará su devolución de llamada en la route1 .