How to create a sleep/delay in nodejs that is Blocking?

Javascriptnode.jsSleepBlockingTimedelay

Javascript Problem Overview


I'm currently trying to learn nodejs and a small project I'm working is writing an API to control some networked LED lights.

The microprocessor controlling the LEDs has a processing delay, and I need to space commands sent to the micro at least 100ms apart. In C# I'm used to just calling Thread.Sleep(time), but I have not found a similar feature in node.

I have found several solutions using the setTimeout(...) function in node, however, this is asynchronous and does not block the thread ( which is what I need in this scenario).

Is anyone aware of a blocking sleep or delay function? Preferably something that does not just spin the CPU, and has an accuracy of +-10 ms?

Javascript Solutions


Solution 1 - Javascript

Node is asynchronous by nature, and that's what's great about it, so you really shouldn't be blocking the thread, but as this seems to be for a project controlling LED's, I'll post a workaraound anyway, even if it's not a very good one and shouldn't be used (seriously).

A while loop will block the thread, so you can create your own sleep function

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

to be used as

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

I think this is the only way to block the thread (in principle), keeping it busy in a loop, as Node doesn't have any blocking functionality built in, as it would sorta defeat the purpose of the async behaviour.

Solution 2 - Javascript

With ECMA script 2017 (supported by Node 7.6 and above), it becomes a 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")
  });
}

Solution 3 - Javascript

The best solution is to create singleton controller for your LED which will queue all commands and execute them with specified delay:

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

Now you can call Led.exec and it'll handle all delays for you:

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

Solution 4 - Javascript

use Node sleep package. https://www.npmjs.com/package/sleep.

in your code you can use

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

to sleep for a specific n seconds.

Solution 5 - Javascript

Just use child_process.execSync and call the system's sleep function.

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

I use this in a loop at the top of my main application script to make Node wait until network drives are attached before running the rest of the application.

Solution 6 - Javascript

Easiest true sync solution (i.e. no yield/async) I could come up with that works in all OS's without any dependencies is to call the node process to eval an in-line setTimeout expression:

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

Solution 7 - Javascript

It's pretty trivial to implement with native addon, so someone did that: https://github.com/ErikDubbelboer/node-sleep.git

Solution 8 - Javascript

I found something almost working here 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);`

The unique problem is the date printed isn't correct but the process at least is sequential.

Solution 9 - Javascript

Blocking in Node.js is not necessary, even when developing tight hardware solutions. See temporal.js which does not use setTimeout or setIntervalsetImmediate. Instead, it uses setImmediate or nextTick which give much higher resolution task execution, and you can create a linear list of tasks. But you can do it without blocking the thread.

Solution 10 - Javascript

You can simply use yield feature introduced in ECMA6 and gen-run library:

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

Solution 11 - Javascript

asynchronous call ping command to block current code to execution in specified milliseconds.

  • ping command is Cross-platform
  • start /b means: start program but not show window.

code as below:

const { execSync } = require('child_process')
// delay(blocking) specified milliseconds
function sleep(ms) {
    // special Reserved IPv4 Address(RFC 5736): 192.0.0.0
    // refer: https://en.wikipedia.org/wiki/Reserved_IP_addresses
    execSync(`start /b ping 192.0.0.0 -n 1 -w ${ms} > nul`)
}

// usage
console.log("delay 2500ms start\t:" + (new Date().getTime() / 1000).toFixed(3))
sleep(2500)
console.log("delay 2500ms end\t:" + (new Date().getTime() / 1000).toFixed(3))

notice important: Above is not a precision solution, it just approach the blocking time

Solution 12 - Javascript

As the sleep package author suggests *:

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

function sleep(n) {
  msleep(n * 1000);
}

Solution 13 - Javascript

blocking the main thread is not a good style for node because in most cases more then one person is using it. You should use settimeout/setinterval in combination with callbacks.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionon3alView Question on Stackoverflow
Solution 1 - JavascriptadeneoView Answer on Stackoverflow
Solution 2 - JavascriptHRJView Answer on Stackoverflow
Solution 3 - JavascriptLeonid BeschastnyView Answer on Stackoverflow
Solution 4 - JavascriptManoj SanjeewaView Answer on Stackoverflow
Solution 5 - JavascriptsffcView Answer on Stackoverflow
Solution 6 - JavascriptmythzView Answer on Stackoverflow
Solution 7 - JavascriptvkurchatkinView Answer on Stackoverflow
Solution 8 - JavascriptAlexView Answer on Stackoverflow
Solution 9 - JavascriptBrian GenisioView Answer on Stackoverflow
Solution 10 - JavascriptNaWeeDView Answer on Stackoverflow
Solution 11 - Javascriptgsw945View Answer on Stackoverflow
Solution 12 - Javascript8ctopusView Answer on Stackoverflow
Solution 13 - JavascriptCracker0dksView Answer on Stackoverflow