javascript - pause - timers nodejs
¿Cómo crear un sleep/delay en nodejs que está bloqueando? (11)
Con el script ECMA 2017 (compatible con el Nodo 7.6 y superior), se convierte en una sola línea:
function sleep(millis) {
return new Promise(resolve => setTimeout(resolve, millis));
}
// Usage in async function
async function test {
await sleep(1000)
console.log("one second has elapsed")
}
// Usage in normal function
function test2 {
sleep(1000).then(() => {
console.log("one second has elapsed")
});
}
Actualmente estoy tratando de aprender nodejs y un pequeño proyecto en el que estoy trabajando es escribir una API para controlar algunas luces LED en red.
El microprocesador que controla los LED tiene un retraso de procesamiento, y necesito espaciar los comandos enviados al micro por lo menos a 100 ms de distancia. En C # estoy acostumbrado a llamar a Thread.Sleep (hora), pero no he encontrado una característica similar en el nodo.
He encontrado varias soluciones utilizando la función setTimeout (...) en el nodo, sin embargo, esto es asíncrono y no bloquea el subproceso (que es lo que necesito en este escenario).
¿Alguien es consciente de un bloqueo del sueño o de una función de retraso? ¿Preferiblemente algo que no solo hace girar la CPU y tiene una precisión de + -10 ms?
El bloqueo en Node.js no es necesario, incluso cuando se desarrollan soluciones de hardware ajustadas. Consulte temporal.js que no usa setTimeout
o setInterval
setImmediate. En su lugar, utiliza setImmediate
o nextTick
que proporciona una ejecución de tareas con una resolución mucho mayor, y puede crear una lista lineal de tareas. Pero puedes hacerlo sin bloquear el hilo.
El nodo es asíncrono por naturaleza, y eso es lo que tiene de bueno, así que realmente no deberías estar bloqueando el hilo, pero como parece ser para un proyecto que controla los LED, publicaré un workaraound de todos modos, incluso si no es muy bueno y no debe ser usado (en serio).
Un bucle while bloqueará el hilo, por lo que puede crear su propia función de suspensión
function sleep(time, callback) {
var stop = new Date().getTime();
while(new Date().getTime() < stop + time) {
;
}
callback();
}
para ser utilizado como
sleep(1000, function() {
// executes after one second, and blocks the thread
});
Creo que esta es la única forma de bloquear el subproceso (en principio), manteniéndolo ocupado en un bucle, ya que Node no tiene ninguna funcionalidad de bloqueo incorporada, ya que de algún modo anularía el propósito del comportamiento asíncrono.
Encontré algo que casi funciona aquí https://.com/questions/21819858/how-to-wrap-async-function-calls-into-a-sync-function-in-node-js-or-ja vascript
`function AnticipatedSyncFunction(){
var ret;
setTimeout(function(){
var startdate = new Date()
ret = "hello" + startdate;
},3000);
while(ret === undefined) {
require(''deasync'').runLoopOnce();
}
return ret;
}
var output = AnticipatedSyncFunction();
var startdate = new Date()
console.log(startdate)
console.log("output="+output);`
El único problema es que la fecha de impresión no es correcta, pero al menos el proceso es secuencial.
Es bastante trivial implementarlo con un complemento nativo, así que alguien lo hizo: https://github.com/ErikDubbelboer/node-sleep.git
La mejor solución es crear un controlador Singleton para su LED, que pondrá en cola todos los comandos y los ejecutará con un retraso específico:
function LedController(timeout) {
this.timeout = timeout || 100;
this.queue = [];
this.ready = true;
}
LedController.prototype.send = function(cmd, callback) {
sendCmdToLed(cmd);
if (callback) callback();
// or simply `sendCmdToLed(cmd, callback)` if sendCmdToLed is async
};
LedController.prototype.exec = function() {
this.queue.push(arguments);
this.process();
};
LedController.prototype.process = function() {
if (this.queue.length === 0) return;
if (!this.ready) return;
var self = this;
this.ready = false;
this.send.apply(this, this.queue.shift());
setTimeout(function () {
self.ready = true;
self.process();
}, this.timeout);
};
var Led = new LedController();
Ahora puede llamar a Led.exec
y manejará todos los retrasos por usted:
Led.exec(cmd, function() {
console.log(''Command sent'');
});
La solución de sincronización verdadera más fácil (es decir, sin rendimiento / asíncrono) que podría funcionar que funciona en todos los sistemas operativos sin ninguna dependencia es llamar al proceso del nodo para setTimeout
expresión setTimeout
en línea:
const sleep = (ms) => require("child_process")
.execSync(`"${process.argv[0]}" -e setTimeout(function(){},${ms})`);
Simplemente puede usar la función de yield
introducida en ECMA6 y gen-run
library:
let run = require(''gen-run'');
function sleep(time) {
return function (callback) {
setTimeout(function(){
console.log(time);
callback();
}, time);
}
}
run(function*(){
console.log("befor sleeping!");
yield sleep(2000);
console.log("after sleeping!");
});
Simplemente use child_process.execSync
y llame a la función de suspensión del sistema.
//import child_process module
const child_process = require("child_process");
// Sleep for 5 seconds
child_process.execSync("sleep 5");
// Sleep for 250 microseconds
child_process.execSync("usleep 250");
// Sleep for a variable number of microseconds
var numMicroSeconds = 250;
child_process.execFileSync("usleep", [numMicroSeconds]);
Lo uso en un bucle en la parte superior de mi script principal de la aplicación para hacer que Node espere hasta que las unidades de red estén conectadas antes de ejecutar el resto de la aplicación.
bloquear el hilo principal no es un buen estilo para el nodo porque en la mayoría de los casos, más de una persona lo está utilizando. Debe usar settimeout / setinterval en combinación con devoluciones de llamada.
use el paquete de sueño Node. https://www.npmjs.com/package/sleep .
en tu código puedes usar
var sleep = require(''sleep'');
sleep.sleep(n)
Para dormir durante unos n segundos específicos.