Подтвердить что ты не робот

Как создать сон/задержку в nodejs, который блокирует?

В настоящее время я пытаюсь изучить nodejs и небольшой проект, над которым я работаю, пишет API для управления некоторыми сетевыми светодиодами.

Микропроцессор, управляющий светодиодами, имеет задержку обработки, и мне нужно передать команды, переданные микропроцессу, по меньшей мере, на 100 мсек. В С# я использую просто вызов Thread.Sleep(время), но я не нашел подобную функцию в node.

Я нашел несколько решений, используя функцию setTimeout (...) в node, однако это асинхронно и не блокирует поток (который мне нужен в этом сценарии).

Кто-нибудь знает о блокировке функции сна или задержки? Предпочтительно что-то, что не просто вращает процессор, и имеет точность + -10 мс?

4b9b3361

Ответ 1

Лучшим решением является создание одноточечного контроллера для вашего светодиода, который будет ставить в очередь все команды и выполнять их с указанной задержкой:

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

Теперь вы можете вызвать Led.exec, и он будет обрабатывать все задержки для вас:

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

Ответ 2

Node является асинхронным по своей природе, и что в этом хорошего, поэтому вы действительно не должны блокировать поток, но поскольку это похоже на проект, управляющий светодиодами, я все равно опубликую workaraound, даже если он не очень хороший и не следует использовать (серьезно).

Цикл while блокирует поток, поэтому вы можете создать свою собственную функцию сна

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

который будет использоваться как

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

Я думаю, что это единственный способ блокировать поток (в принципе), сохраняя его занятым в цикле, так как Node не имеет встроенных функций блокировки, поскольку он сорвал бы цель асинхронизации поведение.

Ответ 3

используйте Node пакет сна. https://www.npmjs.com/package/sleep.

в вашем коде вы можете использовать

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

чтобы спать в течение определенных секунд.

Ответ 4

Просто используйте child_process.execSync и вызовите функцию спящего режима.

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

Я использую это в цикле в верхней части моего основного приложения script, чтобы сделать Node до тех пор, пока не будут подключены сетевые диски перед запуском остальной части приложения.

Ответ 6

Блокировка в Node.js не требуется, даже при разработке жестких аппаратных решений. См temporal.js, который не использует setTimeout или setInterval setImmediate. Вместо этого он использует setImmediate или nextTick которые обеспечивают выполнение гораздо более высокого разрешения, и вы можете создать линейный список задач. Но вы можете сделать это, не блокируя поток.

Ответ 7

Я нашел что-то почти работающее здесь https://stackoverflow.com/questions/21819858/how-to-wrap-async-function-calls-into-a-sync-function -in- node -js или-я 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);`

Единственная проблема - напечатанная дата неверна, но процесс по крайней мере последователен.

Ответ 8

Самое простое истинное решение для синхронизации (т.е. Отсутствие /async). Я мог бы придумать, что работа во всех ОС без каких-либо зависимостей заключается в вызове процесса узла для вычисления встроенного выражения setTimeout:

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

Ответ 9

Вы можете просто использовать функцию yield введенную в ECMA6 и библиотеку 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!");
});

Ответ 10

С ECMA-скриптом 2017 (поддерживается узлом 7.6 и выше) он становится однострочным:

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

Ответ 11

блокировка основного потока не является хорошим стилем для node, потому что в большинстве случаев более одного человека использует его. Вы должны использовать setimeout/setinterval в сочетании с обратными вызовами.