2012-01-21 31 views
5

Si tengo una función simple setTimeout() y la configuro durante 10 segundos ...En Node.js, ¿setTimeout() bloquea el bucle de evento?

¿El servidor completo está muerto dentro de esos 10 segundos? ¿Es esto cierto? Eso fue lo que oí.

+1

Respuesta corta: no. – voithos

+0

@voithos, entonces, ¿qué es esto? http://stackoverflow.com/questions/8949465/node-js-how-would-you-recreate-the-settimeout-function-without-it-blocking-th – TIMEX

+1

¿Has leído las respuestas en ese enlace? No es 'setTimeout' que estaba bloqueando el bucle de evento, sino la función' wait() 'que implementaron. ¡Literalmente, simplemente esperó la cantidad de tiempo dada (con un ciclo while, nada menos)! Por supuesto que bloquearía. 'setTimeout' no funciona de esa manera. – voithos

Respuesta

19

La respuesta es no. Lo que mostró su enlace Node.js: How would you recreate the 'setTimeout' function without it blocking the event loop? no era un setTimeout bloqueando el bucle de evento era un while bucle que deliberadamente bloquea el bucle de evento. Si desea que su servidor sea rápido, no desea bloquear el ciclo de eventos. Una devolución de llamada asincrónica como setTimeout funcionará de maravilla.

¿Estás tratando de bloquear por alguna razón (como las pruebas o algo?)

+0

Además, todo lo anterior también se aplica a setInterval. – alessioalex

2

Eso no es cierto. Cuando llama al setTimeout y devuelve el código, el servidor no está bloqueado. Es libre de procesar otros eventos (posiblemente otras devoluciones de llamada setTimeout) mientras espera que su temporizador particular dispare

2

El vínculo que usted parece estar confundido sobre lo hace no setTimeout estado que va a bloquear. Más bien, el OP en esa pregunta estaba tratando de hacer una función personalizada llamada wait que se comportaría como setTimeout. La función wait es la función de bloqueo - setTimeout no bloqueará.

4

Otro hallazgo que puede ayudar a otros que están aprendiendo Node.js y es curioso de esta pregunta, pero engañado por un comportamiento oculto de los navegadores modernos.

El código es realmente simple, solo quiero probar mi comprensión de la "naturaleza asíncrona" de Node.js.

var express = require('express'); 
var router = express.Router(); 

router.get('/', function(req, res, next) { 
    console.log("route begin"); 
    var start = new Date(); 


    setTimeout(function() { 
     res.render('index', { title: start + ' - ' + new Date()}); 
    }, 20000);//force delay of 20 seconds. 

    console.log("route end"); 
}); 

module.exports = router; 

Si comienzo a tres ventanas del navegador (Firefox, con mayor precisión), abra la URL definida por esta vía, al mismo tiempo, y comprobar el registro de la consola de Node.js, está claro que la petición no es manejado concurrentemente!

Probé la prueba varias veces, los resultados son los mismos.

La salida del registro típico es la siguiente:

route begin at: Fri Aug 28 2015 18:35:57 GMT+0800 (CST) 
route end at: Fri Aug 28 2015 18:35:57 GMT+0800 (CST) 
route begin at: Fri Aug 28 2015 18:36:18 GMT+0800 (CST) 
route end at: Fri Aug 28 2015 18:36:18 GMT+0800 (CST) 
route begin at: Fri Aug 28 2015 18:36:20 GMT+0800 (CST) 
route end at: Fri Aug 28 2015 18:36:20 GMT+0800 (CST) 

Y también, curiosamente, no se ejecuta en modo de serie o bien (si Node.js es bloqueado por setTimeout, debería). El intervalo entre la primera y la segunda solicitud es de 20 segundos, pero el segundo y el tercero son solo 2 segundos.

Después de rascarme la cabeza por un buen rato, de repente recuerdo que el navegador tiene un límite de conexión en el mismo host!

Por lo tanto, configuré rápidamente otra prueba, pero esta vez al emitir múltiples comandos curl en su lugar.

¡Aleluya!

route begin at: Fri Aug 28 2015 18:42:51 GMT+0800 (CST) 
route end at: Fri Aug 28 2015 18:42:51 GMT+0800 (CST) 
route begin at: Fri Aug 28 2015 18:42:53 GMT+0800 (CST) 
route end at: Fri Aug 28 2015 18:42:53 GMT+0800 (CST) 
route begin at: Fri Aug 28 2015 18:42:55 GMT+0800 (CST) 
route end at: Fri Aug 28 2015 18:42:55 GMT+0800 (CST) 
0

El proceso principal parece ser monothreaded por el anfitrión y bloqueada por un setTimeout o una while.

Sin embargo, hay una alternativa con este código, que funciona como se espera y no bloquear el proceso principal o el bucle de eventos:

var express = require('express') 
var app = express() 

function setTimeoutAsync (callback, time) { 
    setTimeout(function() { 
    callback() 
    }, time) 
    return 0 
} 

app.get('/', function (req, res, next) { 
    console.log("route begin") 
    var start = +new Date() 
    setTimeoutAsync(function() { 
     console.log("route done") 
     res.json({ delay: ((+new Date()) - start) + 'ms' }) 
    }, 5000) 
    console.log("route end") 
}); 

app.listen(8000) 

En el terminal:

route begin // first page 
route end 
route begin // second page 
route end 
route begin // third page 
route end 
route done // first render 
route done // second render 
route done // third render 

Buena fuentes:

https://www.journaldev.com/7462/node-js-architecture-single-threaded-event-loop

https://nodejs.org/en/docs/guides/blocking-vs-non-blocking/

Cuestiones relacionadas