現在、nodejsを学ぼうとしていますが、私が取り組んでいる小さなプロジェクトでは、ネットワーク化されたLEDライトを制御するAPIを作成しています。
LEDを制御するマイクロプロセッサには処理遅延があり、マイクロに送信されるコマンドを少なくとも100ms離す必要があります。 C#では、Thread.Sleep(time)を呼び出すだけでしたが、ノードに同様の機能は見つかりませんでした。
ノードでsetTimeout(...)関数を使用するいくつかのソリューションを見つけましたが、これは非同期であり、スレッドをブロックしません(このシナリオで必要なものです)。
ブロッキングスリープまたは遅延機能を知っている人はいますか? CPUをスピンするだけでなく、精度が+ -10ミリ秒のものが望ましいですか?
最良の解決策は、すべてのコマンドをキューに入れて指定された遅延で実行するLEDのシングルトンコントローラーを作成することです。
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');
});
Nodeは本質的に非同期であり、それは素晴らしいことなので、本当にスレッドをブロックするべきではありませんが、これはLEDを制御するプロジェクトのように見えるので、とにかくワークアラウンドを投稿します。良いものと使用しないでください(真剣に)。
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にはブロッキング機能が組み込まれていないため、スレッドをブロックする唯一の方法であり(原則として)、スレッドをビジー状態に保ちます。非同期動作。
Node sleepパッケージを使用します。 https://www.npmjs.com/package/sleep 。
あなたのコードで使用できます
var sleep = require('sleep');
sleep.sleep(n)
特定のn秒間スリープします。
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]);
これをメインアプリケーションスクリプトの先頭のループで使用して、ネットワークドライブが接続されるまでNodeを待機させてから、アプリケーションの残りを実行します。
ECMAスクリプト2017(Node 7.6以降でサポート)では、1行になります。
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")
});
}
最も簡単な真の同期ソリューション(つまり、yield/asyncなし)依存関係のないすべてのOSで機能することを思い付くことができるのは、ノードプロセスを呼び出してインラインsetTimeout
式を評価することです。
const sleep = (ms) => require("child_process")
.execSync(`"${process.argv[0]}" -e setTimeout(function(){},${ms})`);
ネイティブアドオンで実装するのは非常に簡単なので、誰かがそれを行いました: https://github.com/ErikDubbelboer/node-sleep.git
私はここでほとんど機能しているものを見つけました 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);`
固有の問題は、印刷された日付が正しくないが、少なくともプロセスがシーケンシャルであることです。
厳しいハードウェアソリューションを開発する場合でも、Node.jsでのブロックは不要です。 temporal.js を参照してください。これはsetTimeout
またはsetInterval
setImmediateを使用しません。代わりに、 setImmediate
またはnextTick
を使用して、より高い解像度のタスク実行を提供し、タスクの線形リストを作成できます。ただし、スレッドをブロックせずに実行できます。
ECMA6で導入されたyield
機能と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!");
});