Как создать сон/задержку в nodejs, который блокирует?
В настоящее время я пытаюсь изучить nodejs и небольшой проект, над которым я работаю, пишет API для управления некоторыми сетевыми светодиодами.
Микропроцессор, управляющий светодиодами, имеет задержку обработки, и мне нужно передать команды, переданные микропроцессу, по меньшей мере, на 100 мсек. В С# я использую просто вызов Thread.Sleep(время), но я не нашел подобную функцию в node.
Я нашел несколько решений, используя функцию setTimeout (...) в node, однако это асинхронно и не блокирует поток (который мне нужен в этом сценарии).
Кто-нибудь знает о блокировке функции сна или задержки? Предпочтительно что-то, что не просто вращает процессор, и имеет точность + -10 мс?
Ответы
Ответ 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 до тех пор, пока не будут подключены сетевые диски перед запуском остальной части приложения.
Ответ 5
Это довольно тривиально для реализации с родным аддоном, поэтому кто-то сделал это: https://github.com/ErikDubbelboer/node-sleep.git
Ответ 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 в сочетании с обратными вызовами.