Your computer is never fast enough. However, in rare cases, you need to slow down. In my case, is was OpenStreetMap that forced me to go a slower pace. The free plan only allows one access per second, so I had to make my node.js program pause a second between two accesses.
As it turns out, you can't do that in node.js. Luckily, modern node.js allows you to simulate the feature so you hardly notice the difference.
What about using a library?
In the JavaScript worlds, there's a library for everything. Even for sleeping. But you shouldn't use it.
I'm talking about the library called sleep
(i.e. the one you install with npm install sleep
). At first glance, it's exactly the library you're looking for. It offers methods to stop the execution of your node.js application for a couple of seconds, milliseconds, or microseconds.
At second glance, you'll see the large print on the npm site. The library follows a "stop the world" approach. That may be great for debugging, but it stops everything. If you've initiated a REST call, it won't be processed until the sleep period is over.
In my case, that's not what I needed. I wanted to delay the main thread for a second, but I didn't want to stop the secondary thread to process the result of the REST call. Only there's no such thing as a secondary thread in node.js. There's only one thread with an event loop. The sleep
library pauses precisely this event loop.
Pausing the "main" thread without stopping the "secondary" threads
It's important to keep in mind there's only one thread in node.js. Multi-threading may be a useful metaphor, but in reality the only way to simulate it is to use setTimeout()
or setInterval()
.
So that's the general approach. You wrap the code you want to execute later in a function, which is executed by a setTimeout()
call. The idea is sketched in this StackOverflow answer:
A simpler approach
From a technical point of view, that's the end of the story. It's precisely what I ended with. But from a semantical point of view, there's a lot to be improved. Remember, what I wanted to program was something like this:
var largeBunchOfGPSCoordinates = [{...}, {...}, ..., {...}]; for (var coordinate of largeBunchOfGPSCoordinates) { console.log(determineCity(coordinate)); sleep(1000); }You can express this with setTimeout()
, but it's going to be clumsy.
Async/Await to the rescue
Modern JavaScript helps you with async
and await
. You can express the algorithm like so:
JavaScript internally unwraps the for
loop in a sequence of promises. The next loop is started by the resolve
callback of the sleep
method.
From a programmers perspective, that's a nice an clean solution. You only have to add the keywords async
and await
. Apart from that, the programming model doesn't change much.
forEach()
For some reason, this approach only works with the traditional for
loop. It does not work with the fancy, functional forEach()
method.
Wrapping it up
Node.js doesn't allow you to put the application asleep, but you can simulate this by using setTimeout()
. That, in turn, throws you directly into callback hell. There's nothing you can do about this. But async / await
offers nice syntactic sugar to make the callback hell go away, if only virtually.