73

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?

on3al
  • 2,090
  • 4
  • 20
  • 19
  • 4
    Sounds to me like you're using the wrong tool for the job. Node was designed to be _non_ blocking, if you want to create a blocking daemon of sorts, you should look into alternative technologies. accuracy of ~10ms in network contexts is easily doable in most languages.... – Elias Van Ootegem Jan 07 '14 at 08:36
  • 1
    Or, you could do it the "node" way, use async style to re-model your program logic. – Passerby Jan 07 '14 at 08:37
  • 1
    Are you *sure* you need to block the thread? If you're new to nodejs, then it might just be that you're not used to thinking/designing flow in asynchronous terms yet :) Anyway, there's a sleep package here: https://npmjs.org/package/sleep (real sleep where supported, busy-wait for windows) – Supr Jan 07 '14 at 08:56
  • Yup, dealing with hardware, you need control over the low-level details. Your program itself may take some execution time, which you have to adjust. If precise scheduling is of utmost importance node.js may not be suitable for your needs. – user568109 Jan 07 '14 at 09:03
  • 1
    That doesn't necessarily imply that it needs to be blocking though, unless setTimeout has too much overhead. I just made a simple test: http://jsapp.us/#s445.js Running this gives at most 6 ms delay using setTimeout, while blocking is ranging up to 39 ms delay (worst cases are probably due to server being busy with other things, so may not apply in OPs case). But I agree that node.js is probably not suitable if absolute 100% precision and reliability is required. – Supr Jan 07 '14 at 11:26
  • `setTimeout(function(){ console.log("Delayed"); }, 100);` However, IIRC, it's not necessarily accurate to 10ms. That is more "node" in style. To avoid callback hell, look at asyncawait or iced coffeescript. – SilentSteel Aug 26 '14 at 15:14
  • 1
    There **are** legit cases when a blocking solution is needed, for instance, in debugging: to simulate delays while keeping full control over the order of execution. The fact that Node.js doesn't provide a direct solution (although it could) is a deficit of Node, which should *not* be advertised as a feature, nor used as an excuse for blaming the questioner who asked a sound question. – Marcin Wojnarski Dec 16 '21 at 00:59

13 Answers13

73

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.

Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
adeneo
  • 312,895
  • 29
  • 395
  • 388
  • 27
    I think, the right words are "should never be used", because this is a busy waiting. – Bakudan Jan 07 '14 at 08:45
  • 8
    @Bakudan - depends, it should never really be used for a webserver, but Node is used for many other things, and in this case the OP is controlling LED's and specifically asks for something to block the thread, and this does that. – adeneo Jan 07 '14 at 08:51
  • Excellent, but why can't he just set a timeout ? – ShrekOverflow Jul 16 '14 at 13:39
  • 1
    I needed a quick&dirty solution for a test during debugging to ensure that refactoring using the 'preferred way' would actually solve my problem - it didn't, so those lines did save me some time. – Zefiro Dec 07 '14 at 17:50
  • 8
    Personally, I think that Node.js needs sleep-based blocking. It's wrong to suggest that the author(s) of Node knew all scenarios. What if you need to slow down your activities so that you're not overrunning other people's servers and resources? It's bad netiquette to wear out someone else's, say, email server just because you have a million outbound emails to send and your platform of choice doesn't appear to allow anything to add delays. Thanks, adeneo. – Michael Blankenship May 09 '15 at 21:53
  • 2
    There are several [npm modules](https://www.npmjs.com/search?q=sleep) available for doing a sleep-based blocking. – Timothy Gu May 23 '15 at 01:16
  • 2
    And most of those modules are written after this answer was posted, and using the exact same technique. – adeneo Jul 31 '15 at 22:41
  • extremely `dangerous` but nifty solution! – loretoparisi Mar 11 '16 at 14:03
  • Is the callback necessary there? Won't the returning of the function be delayed until after the while-loop anyway? – Mark K Cowan Nov 20 '16 at 23:23
  • 1
    @MarkKCowan - as it's blocking the entire thread, the callback isn't really neccessary, one could just do `sleep(1000); alert()` and the thread would be blocked for a second before the alert etc. – adeneo Nov 20 '16 at 23:28
  • @adeneo: I'm just curious as to why a synchronous function was written with a tailed callback in the first place... – Mark K Cowan Nov 20 '16 at 23:29
  • @MarkKCowan - looks cooler, and is more what most people are used to in Node – adeneo Nov 21 '16 at 00:48
  • this does not work, the event loop will still tick in this solution – Bamieh Jul 31 '17 at 08:07
  • There are only 2 ways to truly "block" the thread in Node. Using a userspace spin lock or busy wait, or relying on the operating system (kernel space) to deschedule the Node thread (which is usually done by running the system sleep function, but there are other alternatives like posix clock functions, or relying on blocking calls to syscalls like OS locks or relying on child OS processes running sleep). – CMCDragonkai Sep 19 '17 at 07:51
  • I just needed to simulate some wait between an insertion db query. – igauravsehrawat Feb 06 '18 at 06:24
  • This is now pretty easy, thanks to `async` / `await`: ``` await new Promise(resolve => { setTimeout(resolve, timeInMilliseconds); }); ``` – jacobq Jan 15 '19 at 21:16
  • "Preferably something that does not just spin the CPU" – Drew Delano Apr 17 '22 at 07:38
43

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")
  });
}
lolesque
  • 10,693
  • 5
  • 42
  • 42
HRJ
  • 17,079
  • 11
  • 56
  • 80
  • 2
    This is the most practical way to sleep for applications. However, people should understand that this is not the same as the sleep system call (aka Thread.sleep()) and the contract is that you make the app sleep for *at least* the given amount, plus the time the callback is queuing in the event queue (typically less than 10 ms). – Elias Toivanen Dec 14 '21 at 18:09
  • 11
    This function is *non-blocking*, while the question explicitly asks for a **blocking** solution. – Marcin Wojnarski Dec 16 '21 at 00:28
  • This is FANTASTIC! HRJ, you helped me after frustratingly failing to get this to work. (I'm new to typescript) – Sander Bouwhuis Jun 02 '22 at 07:26
42

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');
});
Leonid Beschastny
  • 50,364
  • 10
  • 118
  • 122
  • 11
    I can't believe simple things are so complicated in NodeJS. God bless C# and/or Java! – TriCore May 01 '18 at 02:04
  • 2
    @TriCore hopefully, NodeJS support ES6 and `async`/`await` now. So timeouts and async operations are no longer that complicated. – Leonid Beschastny May 01 '18 at 11:32
  • 7
    @TriCore God bless Node for making stupid things so complicated, because blocking a single thread is definitely stupid (this doesn't apply to the answer, which is technically wrong because it's non-blocking). @LeonidBeschastny Actually, generators and `co` existed at the time when the question was asked. Currently `async..await` is certainly a way to go. – Estus Flask Jan 22 '19 at 23:04
  • ReferenceError: sendCmdToLed is not defined – Jortega Sep 21 '20 at 15:54
37

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.

Maxim Krizhanovsky
  • 26,265
  • 5
  • 59
  • 89
sffc
  • 6,186
  • 3
  • 44
  • 68
  • child_process.execSync("sleep 1"); ^ ReferenceError: child_process is not defined – sapy Aug 16 '17 at 09:55
  • 3
    @sapy You need to include the child_process module. For example, `const child_process = require("child_process");` – sffc Aug 17 '17 at 22:16
35

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.

Manoj Sanjeewa
  • 1,069
  • 1
  • 11
  • 34
8

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})`);
mythz
  • 141,670
  • 29
  • 246
  • 390
  • 3
    This is a nice solution, and using `spawnSync()` instead avoids escaping issues: `spawnSync(process.argv[0], ['-e', 'setTimeout(function(){},' + ms + ')']);` and works Windows/Linux – bonger Jun 27 '18 at 16:59
3

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);
}
8ctopus
  • 2,617
  • 2
  • 18
  • 25
  • Best answer. A great solution (although it Nodejs seems to have meant to not allow sync wait, yet, better than the busy waiting using while since that blocks Node's event queue ). – Sohail Si May 04 '22 at 09:08
2

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

vkurchatkin
  • 13,364
  • 2
  • 47
  • 55
  • 2
    This is mainly useful for debugging purpose or for writing tests. It's a very bad idea to use blocking sleep in production. – Leonid Beschastny Jan 07 '14 at 12:36
  • 2
    sure it is, in most cases. but «production» is a broad term. if you don't need to serve clients, then you can do blocking things. – vkurchatkin Jan 07 '14 at 13:17
  • 3
    it is ok if you know what are you doing, js is not just for client-server apps. – setec Oct 17 '14 at 09:09
  • If "production" is a bunch of command-line tools for administrators to use (written in node, to use protocol/client code from the main codebase), then lack of synchronous/blocking stuff in node is a total PITA... Async stuff is a "very bad idea in production" in some cases, given the extra testing needed... – Mark K Cowan Nov 20 '16 at 23:31
  • this should be the accepted solution! the only one that actually block the event loop. – Bamieh Jul 31 '17 at 08:08
2

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.

flaschbier
  • 3,910
  • 2
  • 24
  • 36
Zioalex
  • 3,441
  • 2
  • 33
  • 30
1

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.

jpaugh
  • 6,634
  • 4
  • 38
  • 90
Brian Genisio
  • 47,787
  • 16
  • 124
  • 167
  • 6
    Blocking in Node.js is necessary for testing, e.g. when simulating an overloaded server, which does not respond to every request within a timeout. – Pavel Gatnar Aug 30 '16 at 15:50
  • Sometimes it's necessary if other codes are written in returning-style and you don't know how to change all of them to callback-style. – Romulus Urakagi Ts'ai Jan 24 '17 at 08:07
  • @RomulusUrakagiTs'ai "Necessary"? I'd be interested in seeing that example. Can you supply a gist? – Brian Genisio Jan 24 '17 at 12:38
  • `this.get({'/somepath': function(){ return sendFile('foobar.json').call(this); });` This is a response function, how can you make it wait something without blocking it? – Romulus Urakagi Ts'ai Jan 25 '17 at 02:07
  • @RomulusUrakagiTs'ai What API is that? What do you need to wait for? I'm not following. You mean you need to wait an amount of time? If so, you can use `setTimeout()` for that... but I'm guessing you are suggesting something else? – Brian Genisio Jan 25 '17 at 04:03
  • It's some generated nodejs/express server code, and you can't `setTimeout()` a return statement. The expected behavior is "blocking waiting something, then return from this function". Waiting what is not important. – Romulus Urakagi Ts'ai Jan 25 '17 at 07:45
  • @RomulusUrakagiTs'ai You are mistaken. Express is inherently asynchronous... in an Express handler, you can make another async call and then return the response when it is complete... I don't know what the inner stuff is (`sendFile`), but you can (as an example) do something like this: `(request, response) => { setTimeout(() => sendFile('', response).call(this), 1000); }`. In other words, you can respond on the `respond` object whenever you want... immediately OR 3 years from now in an an async way. – Brian Genisio Jan 26 '17 at 02:21
  • It's not my code, and I don't understand the original code (it's a generated code), and it requires immediately return. I can't modify the existing code to the structure as your example since I don't know how to. That's why we need a workaround method. – Romulus Urakagi Ts'ai Feb 03 '17 at 02:50
  • @RomulusUrakagiTs'ai I'm not sure what else to say. Node.js is a single-threaded asynchronous programming model. There is no blocking sleep/delay available to you. In fact, most IO models don't block either. There are a couple of legacy filesystem calls that optionally block, but they are discouraged in use (like in connect/express) because they block any incoming requests. And there aren't any blocking delays. I suppose you _could_ write a `while` loop that constantly checks the current time to the original time, but that would be a busy delay... one that would consume a ton of processor. – Brian Genisio Feb 04 '17 at 12:39
  • Well I just want to say sometimes it's practically necessary to block, while is not technically necessary or possible. – Romulus Urakagi Ts'ai Feb 06 '17 at 01:45
1

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!");
});
NaWeeD
  • 561
  • 5
  • 15
1

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

gsw945
  • 88
  • 2
  • 6
-6

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.

Josh Crozier
  • 233,099
  • 56
  • 391
  • 304
Cracker0dks
  • 2,422
  • 1
  • 24
  • 39
  • 2
    I understand it isn't good practice, but in this scenario it's exactly what I need. Node will be controlling a udp server sending commands to a microprocessor controlling light bulb. The micro can only handle a single command at a time, so Node needs to block the thread so other only a single person can control the light at a time. – on3al Jan 14 '14 at 05:34
  • 7
    `blocking the main thread is not good style for ...` is good advice for software that is supposed to run with concurrency, but it's perfect style for the OP's task, regardless of whether it's done in ASM, JS or even PHP. Let's put an end to these mindless "blocking is bad" and "synchronous is satan" cults... – Mark K Cowan Nov 20 '16 at 23:22