web-dev-qa-db-fra.com

Comment créer un sommeil/retard dans nodejs qui bloque?

J'essaie actuellement d'apprendre des nœuds et un petit projet sur lequel je travaille est l'écriture d'une API pour contrôler certaines lumières DEL en réseau.

Le microprocesseur contrôlant les voyants a un délai de traitement, et j'ai besoin d'espacer les commandes envoyées au micro à au moins 100 ms. En C #, je suis habitué à appeler Thread.Sleep (heure), mais je n'ai pas trouvé de fonctionnalité similaire dans node.

J'ai trouvé plusieurs solutions à l'aide de la fonction setTimeout (...) dans le noeud. Cependant, il s'agit d'un processus asynchrone qui ne bloque pas le thread (ce dont j'ai besoin dans ce scénario).

Quelqu'un est-il au courant d'une fonction de blocage du sommeil ou du retard? De préférence, quelque chose qui ne fait pas que tourner le processeur et qui a une précision de + -10 ms?

45
on3al

La meilleure solution consiste à créer un contrôleur singleton pour votre voyant, qui mettra en file d'attente toutes les commandes et les exécutera dans les délais spécifiés:

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();

Maintenant, vous pouvez appeler Led.exec et il gérera tous les délais pour vous:

Led.exec(cmd, function() {
  console.log('Command sent');
});
37
Leonid Beschastny

Le nœud est asynchrone par nature, et c'est ce qui est génial, vous ne devriez donc pas bloquer le fil, mais comme cela semble être pour un projet contrôlant des LED, je posterai quand même un workaround, même si ce n'est pas très bon et ne devrait pas être utilisé (sérieusement).

Une boucle while bloquera le fil, vous permettant ainsi de créer votre propre fonction de veille.

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

être utilisé comme

sleep(1000, function() {
   // executes after one second, and blocks the thread
});

Je pense que c'est le seul moyen de bloquer le thread (en principe), de le garder occupé dans une boucle, car Node n'a aucune fonctionnalité de blocage intégrée, car cela annulerait en quelque sorte le but du comportement asynchrone.

56
adeneo

utilisez le paquet de sommeil Node. https://www.npmjs.com/package/sleep .

dans votre code, vous pouvez utiliser 

var sleep = require('sleep'); 
sleep.sleep(n)

dormir pendant un n secondes spécifique.

26
Manoj Sanjeewa

Utilisez simplement child_process.execSync et appelez la fonction de veille du système.

//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]);

J'utilise ceci dans une boucle en haut de mon script d'application principal pour que Node attende que les lecteurs réseau soient connectés avant d'exécuter le reste de l'application.

17
sffc

Avec le script ECMA 2017 (pris en charge par les nœuds 7.6 et supérieurs), il devient un one-liner:

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")
  });
}
3
HRJ

C'est assez simple à implémenter avec un addon natif, donc quelqu'un l'a fait: https://github.com/ErikDubbelboer/node-sleep.git

2
vkurchatkin

J'ai trouvé quelque chose qui marche presque ici https://stackoverflow.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);`

Le problème unique est que la date imprimée n’est pas correcte mais que le processus est au moins séquentiel.

2
Alex

Easiest true sync solution (c'est-à-dire sans rendement/asynchrone) qui pourrait fonctionner avec tous les systèmes d'exploitation sans dépendance dépend de l'appel du processus de noeud pour évaluer une expression setTimeout en ligne:

const sleep = (ms) => require("child_process")
    .execSync(`"${process.argv[0]}" -e setTimeout(function(){},${ms})`);
2
mythz

Le blocage dans Node.js n’est pas nécessaire, même lors du développement de solutions matérielles strictes. Voir temporal.js qui n'utilise pas setTimeout ou setIntervalsetImmediate. Au lieu de cela, il utilise setImmediate ou nextTick, qui permettent une exécution de tâches d'une résolution bien supérieure, et vous pouvez créer une liste linéaire de tâches. Mais vous pouvez le faire sans bloquer le fil.

1
Brian Genisio

Vous pouvez simplement utiliser la fonctionnalité yield introduite dans ECMA6 et la bibliothèque gen-run:

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!");
});
0
NaWeeD