2012-10-13 103 views
9

Sabiendo que mientras Node.js está trabajando de forma asíncrona, escribir algo como esto:Node.js: mientras devolución de llamada bucle no funciona como se esperaba

function sleep() { 
    var stop = new Date().getTime(); 
    while(new Date().getTime < stop + 15000) { 
     ; 
    } 
} 

sleep(); 
console.log("done"); 

... llamaría el sueño(), bloquean el servidor de la duración del ciclo while (15 segundos) y simplemente ENTONCES imprimir "hecho" a la consola. Por lo que yo entiendo, esto se debe a que Node.js le está dando acceso a JavaScript solo al hilo principal, y por lo tanto este chiflado detendrá su posterior ejecución.

por lo que entiendo la solución a esto es utilizar devoluciones de llamada:

function sleep(callback) { 
    var stop = new Date().getTime(); 
    while(new Date().getTime() < stop + 15000) { 
     ; 
    } 
    callback(); 
} 

sleep(function() { 
    console.log("done sleeping"); 
}); 

console.log("DONE"); 

así que pensé que imprimiría 'Hecho' y después de 15 segundos. 'hecho dormir', ya que se llama a la función dormir() y se le da un puntero a una función de devolución de llamada. Mientras esta función está funcionando (el ciclo while), se ejecutará la última línea (imprimir 'hecho'). Después de 15 segundos, cuando la función dormir() finaliza, llama a la función de devolución de llamada dada, que luego imprime 'hecho dormir'.

Aparentemente entendí algo mal aquí, porque las dos formas anteriores bloquean. ¿Alguien puede aclarar por favor?

Gracias de antemano, Slagjoeyoco

Respuesta

13

JavaScript y Node.js son de un solo subproceso, lo que significa un simple while bloques; no se pueden procesar solicitudes/eventos hasta que se haya realizado el bloqueo while. Las devoluciones de llamada no resuelven mágicamente este problema, solo ayudan a pasar el código personalizado a una función. En su lugar, iterar usando process.nextTick, que le dará absoluto se refiere a los mismos resultados, pero deja espacio para las solicitudes y eventos para ser procesado, así, es decir, que no bloquee:

function doSleep(callback) { 
    var stop = new Date().getTime(); 

    process.nextTick(function() { 
     if(new Date().getTime() < stop + 15000) { 
      //Done, run callback 
      if(typeof callback == "function") { 
       callback(); 
      } 
     } else { 
      //Not done, keep looping 
      process.nextTick(arguments.callee); 
     } 
    }); 
} 

doSleep(function() { 
    console.log("done sleeping"); 
    console.log("DONE"); 
}); 
+0

Usted está complicando a sí mismo. Un simple setTimeout (devolución de llamada, retardo) debería ser suficiente para producir lo mismo que se indica de forma asincrónica. –

+4

@ FabiánH.jr. el punto es que OP podría estar interesado en entender por qué su 'while' no está funcionando y cómo puede escribirse un' while' de una manera no bloqueante, lo cual es en cierto modo una mejor respuesta que "no importa tu método no funciona, hazlo de esta otra manera ". – Mahn

+0

Bien, gran respuesta en general y ahora que lo mencionas fue bastante perspicaz en el proceso interno de node.js –

2

devoluciones de llamada no son lo mismo que la asincronía, sólo son útiles cuando se desea obtener una devolución de llamada ... ... de una operación asíncrona. En su caso, el método todavía se ejecuta de forma síncrona; El nodo no solo detecta mágicamente que hay una operación de devolución de llamada y de larga ejecución, y lo hace regresar antes de tiempo.

La solución real es usar setTimeout en lugar de un bucle ocupado en otro hilo.

9

Está llamando al sleep de inmediato, y los nuevos bloques de función sleep. Sigue iterando hasta que se cumpla la condición. Debe utilizar setTimeout() para evitar el bloqueo:

setTimeout(function() { 
    console.log('done sleeping'); 
}, 15000); 
0

Como ya se ha mencionado, la ejecución asíncrona puede conseguirse mediante una setTimeout() en lugar de tiempo, porque mientras se congelará en un "marco de la ejecución".

También parece que tiene un error de sintaxis en su ejemplo.

Ésta funciona bien: http://jsfiddle.net/6TP76/

Cuestiones relacionadas