Manejando múltiples solicitudes sin una previa bloqueando la siguiente

Tengo problemas tratando de manejar múltiples solicitudes del cliente. Por derecho, cada ruta debe manejarse de forma asíncrona, sin embargo, no puedo realizar la solicitud de manejo tras solicitud sin que la anterior bloquee la siguiente. Con el siguiente código, estoy usando promesas y usando el enrutador Express.js

let api = Router(); api.get('/a', (req, res, next) => { console.log('A: get all A'); getAllA() .then(() => console.log('A: finish retrieving A')); console.log('A: do something else'); }); api.get('/b', (req, res, next) => { console.log('B: get all B'); getAllB() .then(() => console.log('B: finish retrieving B') console.log('B: do something else'); }); 

Entonces, si solicito / ay luego / b casi instantáneamente, la salida actual es:

 // Request /a 'A: get all A' 'A: do something else' // Request /b 'A: finish retrieving A' 'B: get all B' 'B: do something else' 'B: finish retrieving B' 

Mientras espero que sea algo como esto:

 // Request /a 'A: get all A' 'A: do something else' // Request /b 'B: get all B' 'B: do something else' 'A: finish retrieving A' 'B: finish retrieving B' 

¿Alguna idea de si esto es esperado o hay otras formas de manejar esto?

Un servidor node.js ejecuta solo un hilo de ejecución de Javascript a la vez. En realidad no procesa múltiples solicitudes al mismo tiempo. Por lo tanto, si una solicitud acapara la CPU por un tiempo, ninguna otra solicitud se procesará hasta que la primera solicitud finalice y abandone la CPU.

Pero, si sus solicitudes realizan operaciones asíncronas (E / S de archivos asíncronos, redes asíncronas, configura los temporizadores para hacer algo en el futuro, use alguna biblioteca de terceros que implemente alguna otra operación asíncrona, etc.), luego cada vez que se inicie una solicitud Una operación asíncrona devuelve el control a la cola de eventos, luego otra solicitud puede comenzar a procesarse hasta que finalice o también llegue a una operación asíncrona. Si lo hace o no dependerá enteramente de la sincronización de las cosas. De esta manera, las solicitudes múltiples pueden estar “en vuelo” al mismo tiempo, aunque solo una está ejecutando Javascript a la vez.

Entonces, en su código, realmente depende de lo que estén haciendo getAllA() y getAllB() . Si son operaciones sincrónicas, bloquearán otros subprocesos mientras se ejecutan. Si son operaciones asíncronas, pero se contentan con los mismos recursos (como una base de datos, un archivo o un servidor), pueden causar cierta serialización debido a la dependencia mutua de la disponibilidad de un recurso externo.

Una forma de obtener un verdadero procesamiento de solicitudes en paralelo en node.js es con la agrupación en clúster. Con el agrupamiento de node.js, inicia varios procesos de node.js en la misma computadora (por lo general, aproximadamente el mismo número de procesos que los núcleos de CPU que tiene) y luego cada proceso de node.js puede procesar las solicitudes de forma independiente en paralelo. Si tiene recursos compartidos a los que todos los procesos en el clúster deben acceder, aún tendrá que encontrar una manera de compartirlos entre los procesos (base de datos, repository central personalizado de información compartida, redis, etc.).

Por ejemplo, puede ver varias solicitudes en vuelo al mismo tiempo si hace algo como esto:

 let api = Router(); api.get('/a', (req, res, next) => { console.log('start of a'); setTimeout(function() { console.log('done with a'); res.json({status: "ok", msg: "done with a"}); }, 500); }); api.get('/b', (req, res, next) => { console.log('start of b'); setTimeout(function() { console.log('done with b'); res.json({status: "ok", msg: "done with b"}); }, 500); }); 

Si luego dispara las solicitudes de / a y / b una después de la otra, debería obtener esto en la consola del servidor:

 start of a start of b done with a done with b 

Ambas solicitudes estaban “en vuelo” al mismo tiempo, aunque en realidad no ejecutaban Javascript al mismo tiempo. Nota: utilicé setTimeout() solo para simular una operación asíncrona con un tiempo de respuesta conocido y controlable. Eso puede ser cualquier serie de operaciones asíncronas.