如何在阻塞的nodejs中创建睡眠/延迟?

on3*_*3al 52 javascript sleep timedelay blocking node.js

我正在尝试学习nodejs和我正在工作的一个小项目正在编写一个API来控制一些联网的LED灯.

控制LED的微处理器具有处理延迟,我需要将发送到微处理器的命令间隔至少100ms.在C#中,我习惯只调用Thread.Sleep(时间),但我没有在节点中找到类似的功能.

我在节点中使用setTimeout(...)函数找到了几个解决方案,但是,这是异步的并且不会阻塞线程(这是我在这种情况下所需要的).

有人知道阻塞睡眠或延迟功能吗?最好是不仅能旋转CPU,而且精度为+ -10 ms的东西?

ade*_*neo 61

Node本质上是异步的,这就是它的优点,所以你真的不应该阻塞线程,但是因为这似乎是一个控制LED的项目,我会发布一个工作流程,即使它不是一个非常好的,不应该使用(严重).

while循环将阻塞该线程,因此您可以创建自己的睡眠功能

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

用作

sleep(1000, function() {
   // executes after one second, and blocks the thread
});
Run Code Online (Sandbox Code Playgroud)

我认为这是阻塞线程的唯一方法(原则上),让它在循环中保持忙碌,因为Node没有内置任何阻塞功能,因为它会排序异步行为的目的.

  • 我认为,正确的词是"永远不应该被使用",因为这是一个忙碌的等待. (15认同)
  • @Bakudan - 依赖,它永远不应该用于网络服务器,但Node用于许多其他事情,在这种情况下,OP控制LED,并特别要求阻止线程,这就是这样. (7认同)
  • 就个人而言,我认为Node.js需要基于睡眠的阻止.建议Node的作者知道所有场景是错误的.如果您需要放慢活动速度以避免超出其他人的服务器和资源,该怎么办?穿上别人的电子邮件服务器是不好的网络礼节,因为你有一百万个出站电子邮件要发送,而你选择的平台似乎不允许任何东西增加延迟.谢谢,adeneo. (7认同)
  • 有几个[npm模块](https://www.npmjs.com/search?q=sleep)可用于进行基于睡眠的阻止. (2认同)
  • 大多数这些模块是在发布此答案之后编写的,并使用完全相同的技术. (2认同)

Leo*_*tny 39

最好的解决方案是为您的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();
Run Code Online (Sandbox Code Playgroud)

现在你可以打电话Led.exec,它会为你处理所有延误:

Led.exec(cmd, function() {
  console.log('Command sent');
});
Run Code Online (Sandbox Code Playgroud)

  • @TriCore上帝保佑Node使愚蠢的事情变得如此复杂,因为阻塞单个线程肯定是愚蠢的(这不适用于答案,从技术上讲这是错误的,因为它是非阻塞的)。@LeonidBeschastny实际上,在问这个问题的时候,发电机和`co`就已经存在了。目前,“ async..await”无疑是一种方法。 (6认同)
  • 我不敢相信简单的事情在NodeJS中是如此复杂。上帝保佑C#和/或Java! (3认同)
  • @TriCore希望,NodeJS现在支持ES6和`async` /`await`.因此,超时和异步操作不再那么复杂. (2认同)

Man*_*ewa 30

使用Node睡眠包.https://www.npmjs.com/package/sleep.

在您的代码中,您可以使用

var sleep = require('sleep'); 
sleep.sleep(n)
Run Code Online (Sandbox Code Playgroud)

睡觉特定的n秒.

  • 在ubuntu上有安装问题..这是解决方案.https://github.com/ErikDubbelboer/node-sleep/issues/19#issuecomment-137213184 (2认同)

sff*_*ffc 22

只需使用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]);
Run Code Online (Sandbox Code Playgroud)

我在主应用程序脚本顶部的循环中使用它来使Node等待,直到连接网络驱动器,然后再运行应用程序的其余部分.

  • @sapy您需要包含 child_process 模块。例如,`const child_process = require("child_process");` (3认同)

HRJ*_*HRJ 14

借助ECMA脚本2017(受Node 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")
  });
}
Run Code Online (Sandbox Code Playgroud)

  • 该函数是*非阻塞*,而问题明确要求**阻塞**解决方案。 (12认同)
  • 这是应用程序最实用的睡眠方式。但是,人们应该明白,这与睡眠系统调用(又名 Thread.sleep())不同,合同是让应用程序睡眠*至少*给定的时间,加上回调排队的时间在事件队列中(通常小于 10 毫秒)。 (2认同)

myt*_*thz 5

我想出的最简单的真正同步解决方案(即没有收益/异步),它可以在所有操作系统上运行而没有任何依赖关系,那就是调用节点进程来评估内联setTimeout表达式:

const sleep = (ms) => require("child_process")
    .execSync(`"${process.argv[0]}" -e setTimeout(function(){},${ms})`);
Run Code Online (Sandbox Code Playgroud)

  • 这是一个不错的解决方案,使用`spawnSync()` 可以避免转义问题:`spawnSync(process.argv[0], ['-e', 'setTimeout(function(){},' + ms + ')' ]);` 并且适用于 Windows/Linux (2认同)

8ct*_*pus 5

正如 sleep 包作者建议的那样*

function msleep(n) {
  Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, n);
}

function sleep(n) {
  msleep(n * 1000);
}
Run Code Online (Sandbox Code Playgroud)