For an upcoming project with node.js I need to perform various housekeeping tasks at periodic times. Specifically some tasks every millisecond, others every 20 ms (50 times per
SetInterval functions in javascript are not accurate. You should try to use a high resolution timer.Building accurate Timers in javascript
Look at this doc: http://nodejs.org/api/timers.html#timers_settimeout_callback_delay_arg
It is important to note that your callback will probably not be called in exactly delay milliseconds - Node.js makes no guarantees about the exact timing of when the callback will fire, nor of the ordering things will fire in. The callback will be called as close as possible to the time specified.
This happens because application code blocks the event loop. All timers and I/O events can be handled only on the nextTick
.
You can see this behaviour with this code:
setInterval(function() {
console.log(Date.now());
for (var i = 0; i < 100000000; i++) {
}
}, 1);
Try to change iterations count and see results.
Ideally, the timer will be triggered exactly if the applications tick will last less than one ms. But this is not practicable in a real application.
I Disabled Debugger and tried again.It worked fine for me
The answer happens to be a combination of those given by Vadim and zer02, so I am leaving a write-up here. As Vadim said, the system cannot cope with too frequent updates, and adding some load to the system is not going to help. Or rather the runtime cannot cope; the system should be more than capable of firing the callback every millisecond if needed, but for some unexplained reason often it doesn't want to.
The solution is to use accurate timers, as zer02 commented. Do not be misled by the name; the mechanism used is the same setTimeout(), but the delay is adjusted depending on the time left until the timer should fire. So, if the time is over then the "accurate timer" will call setTimeout(callback, 0) which is run immediately. System load is, surprisingly, less than with setInterval(): about 2% of the CPU instead of 5%, in my very unscientific sample.
This simple function may come in handy:
/**
* A high resolution timer.
*/
function timer(delay, callback)
{
// self-reference
var self = this;
// attributes
var counter = 0;
self.running = true;
var start = new Date().getTime();
/**
* Delayed running of the callback.
*/
function delayed()
{
callback(delay);
counter ++;
var diff = (new Date().getTime() - start) - counter * delay;
if (!self.running) return;
setTimeout(delayed, delay - diff);
}
// start timer
delayed();
setTimeout(delayed, delay);
}
To use, just call new timer(delay, callback);
. (Yes, I reversed the order of the parameters since having the callback first is very annoying.) To stop it, set timer.running = false
.
One final note: setTimeout(callback, delay) does not use recursion as I feared (as in: wait for some time, then invoke the callback), it just places the callback in a queue which will be called by the runtime when its turn comes, in the global context.