I'm trying to have a loop in my NodeJS Environment that will execute 30 times a second (Based on a fixed variable). I've been told that setInterval and setTimeout isn't the way to go in terms of NodeJS as process.nextTick and setImmediate are available to comply with the I/O queue in NodeJS. I've tried using the following code (setImmediate):
var Physics = {
lastTime: (new Date().getTime()),
upsCounter: 0,
ups: 0,
init: function() {
Physics.loop();
},
loop: function() {
var currentTime = (new Date().getTime());
Physics.upsCounter += 1;
if((currentTime - Physics.lastTime) >= 1000) {
Physics.ups = Physics.upsCounter;
Physics.upsCounter = 0;
Physics.lastTime = currentTime;
console.log('UPS: ' + Physics.getUPS());
}
setImmediate(Physics.loop);
},
getUPS: function() {
return this.ups;
}
};
My problem is that Updates Per Second (UPS) is over 400,000, rather than the required 30, and I was wondering if there was any way to limit it down to this number, or an alternative loop structure. Thanks
I've been told that setInterval and setTimeout isn't the way to go in terms of NodeJS
Of course they are when you need a timeout or interval!
setImmediate/nextTick are immediate, which is not what you want. You cannot limit them, they are as fast as possible by design.
If setInterval is not accurate enough or drifting, then use a self-adjusting timer.
You should go ahead and use the setInterval or setTimeout method, but make sure to unref them so they don't hold up the process that would otherwise exit, unless that timer is the main execution for the program.
see: Node Timers API Documentation
javascript
var t = setInterval(myMethod, 100);
t.unref(); //the timer t will not execute if the rest of the program is ready to exit.
Related
I am debugging a node.js (Node version 6.2.1) program with setInterval() in it. The code is very simple:
const log = console.log;
let cnt = 0;
const inc = () => {
const beforeDebug = Date.now();
log('Before debug time', beforeDebug);
debugger;
const afterDebug = Date.now();
log('After debug time', Date.now());
log('Time spent in debug', afterDebug - beforeDebug);
log(`[${cnt++}]`);
};
setInterval(inc, 1000);
```
The strange behaviour that I observe is that the pauses between setInterval() callback execution will depend on how much time I spend in a breakpoint. For example, if I stay in 'debugger' line for 10 seconds and then resume, I will see the next number only in 10 seconds after I resumed.
I checked this behaviour with command line node debugger and node-inspector.
[UPDATE] (added timestamps to code)
Here's an extracted lines of debug session in command line:
Debugger listening on port 5858
connecting to 127.0.0.1:5858 ... ok
< Before debug time 1467952218915
< After debug time 1467952235018
< Time spent in debug 16103
< Before debug time 1467952252123
Basically the time difference between the executions of the callback in the last section is 17105 which is almost exactly <time-in-debug> + <interval-value>
This issue doesn't have a significant practical impact, but I would love to understand the mechanism of timer underneath. Why it behaves in such weird way?
The short answer is that the time used to determine when to trigger callbacks is cached and can get out of sync with a callback's actual insertion time.
How is this possible?
To understand why this happens, it helps to have an idea of how node's timers are implemented (which is very well documented in the source). Here, all we need to remember is that:
Callbacks are stored in a map keyed by timeout. For example, when you run setTimeout(foo, 10), then foo will be added to a list of all callbacks with timeout 10.
Callbacks keep track of the time at which they were inserted. We'll refer to it as insertionTime to keep things simple (it's actually timer._idleStart in the source).
When a timeout kicks in, node records the current time (now) and runs the timeout's callbacks in sequence until either no callbacks are left or a callback's insertion time is such that now - insertionTime < timeout. In that last case, node will delay the next wakeup of this timeout until timeout - (now - insertionTime).
In your case, here is what happens:
t=0, inc is inserted in a callback list with insertionTime=0.
t=1000, the timeout wakes up, records now=1000, and runs inc.
t=3000 (or however long you are debugging for), inc completes and gets reinserted in the callback list (since you are using setInterval), this time with insertionTime=3000.
t=3000, node keeps going through the list of callbacks and finds the newly inserted callback. It computes now - insertionTime = -2000 which is smaller than timeout (because now is still equal to 1000!). It therefore schedules the next callback execution 3000 = 1000 - (-2000) milliseconds later.
t=6000, the timeout wakes up again, records now=6000, and runs inc.
...
You can get some visibility on timer internals by running your program with NODE_DEBUG=timer:
$ NODE_DEBUG=timer node setinterval.js
TIMER 98831: no 1000 list was found in insert, creating a new one
TIMER 98831: timeout callback 1000
TIMER 98831: now: 1067
inc
TIMER 98831: 1000 list wait because diff is -2000
TIMER 98831: timeout callback 1000
TIMER 98831: now: 6072
inc
TIMER 98831: 1000 list wait because diff is -2000
...
As far as I can tell, this looks like a bug in node. I don't see when it would make sense to have a negative diff above.
What can we do about it?
You seem to be asking this more out of curiosity, but in case you ever need to prevent this added delay, you can work around it by making sure that you have at least one other callback for the same timeout. This will force an update to now.
function f() {
var end = Date.now() + 2000;
while (Date.now() < end); // 2 second busy loop.
console.log('f: ' + Date.now());
}
setInterval(f, 1000);
setTimeout(function () {
setInterval(function () {}, 1000);
}, 10); // Small delay to make sure they don't run in the same wakeup.
If we only add f, it would end up running every 5 seconds. However, if we also register the (empty) second callback, f will correctly run every 3 seconds!
Node.js runs your code in one single thread.
When you pause the execution, the consequential callback will also be delayed until you resume.
Here is an alternative example without employing debugger
var blockUntil = Date.now() + 7000;
function f() {
console.log('Before: ', Date.now())
while (Date.now() < blockUntil); // busy loop
console.log(' After: ', Date.now())
}
setInterval(f, 1000);
And I can confirm it can be reproduced without debugger.
Before: 1467966150871
After: 1467966156847
Before: 1467966163851
After: 1467966163851
Before: 1467966164856
After: 1467966164856
Before: 1467966165859
After: 1467966165859
Before: 1467966166864
After: 1467966166864
I created a foreach loop which calls Facebook's API to fetch data. But since the number of calls are too high, it gives an error that JavaScript's maximum call stack size has exceeded and it stops there.
I was thinking of delaying the execution of each iteration after 5 mins or a fix interval of time.
I took help from this question. Now I want to know, does executing each iteration after an interval of time clear the JavaScript call stack or not?
Code:
var updateFeeds = function(){
db.collection("accounts").find({"status": "live"}).toArray(function(err, clients) {
var interval = 10 * 1000;
var i = 0;
clients.forEach(function(client, index, array){
setTimeout( function (i) {
i++;
****code*****
}, interval * i, i);
});
For each client there are almost 5000 request calls inside the code. I want to clear the JavaScript heap memory after completion of each iteration.
Error: FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
Aborted (core dumped)
You can use set timeout with an increasing timeout. You can store each timeout in an object:
var calls = {};
var urls = {
'first': 'http://...',
'second': 'http://...',
}
var timeout = 0;
for (var i in urls) {
calls[i] = setTimeout(function(){
// Make call here with urls[i];
}, timeout);
timeout + 5000; // Adds 5 seconds
}
Then if you need to cancel any of the timeouts, you can use clearTimeout(calls['first'])
The Facebook API is pretty extensive, maybe you can use a different call to get the data from all the calls in one response.
UPDATE: OK, instead using the loop, try to use setInterval and global variables
enter code here
globalArrayIndex = 0
myInterval = setInertval(function(){
globalArrayIndex++
/*code*/
if(noMoremembers)
clearInterval(myInterval)
}, 5000)
I use Express framework, I have this function and I want to run it in intervals since server starts:
setTimeout(function () {
console.log('timeout completed');
}, 1000);
so i put this piece of code to the initial file of Express.js Framework called App.js but it only runs twice, where is the problem and how could I fix it?
The setTimeout function runs only once when that amount of time is completed,
here in your case it is 1s(1000ms).
Instead you may want to use setInterval which does the same thing except that it doesn't stop until you tell it so.
Here is an example :
var max = 3;
var i = 0;
var timer = setInterval(function(){
if(i === max){
// stop the timer from looping.
clearInterval(timer);
}else{
i++;
}
},1000);
Looks like you are describing a cron sort of job, why don't you use any of the many node crons modules instead.
https://www.npmjs.com/package/node-cron
Check that out, pretty straight forward.
I have a 3rd party tool that hosts their JavaScript on a CDN and I dont want to implement a custom version script due to the amount of changes, rapid development, they make. Part of their JavaScript executes a setInterval with a timer of 8 minutes.
I was wondering if it was possible to access the Timer stack and modify the 8 minutes to 100 seconds for all subsequent timer events?
If not, would a suggested alternative approach be to re-write/override the setInterval function with my own custom js and make sure my custom js loads first before all other js, and then modify the timeout with a matching if condition, if 8 minutes change to 100 seconds? My assumption would be something like this:
window.setInterval = function(callback, timeout) {
//check timeout for 8 minutes
}
Well, I'd try to avoid this at all cost (except to try "for fun").
Here may be the result (a setInterval where all intervals >= 100 seconds are replaced by 100 seconds)
// above the use of setInterval by third party code
(function (w, maxVal) {
var f = w.setInterval;
w.setIntervalOld = f;
w.setInterval = function () {
var a = arguments;
if(a.length >= 2 && (a[1] > maxVal)) {
a[1] = maxVal;
}
f.apply(w, a);
};
})(window, 100000);
I tried to make the hack in the most coherent way and window.setIntervalOld is available for your own code. Tell me what it does for you.
you can do a self-dispatching setTimeout routing instead of using setInterval:
function workload(callback) {
var timeout=5000; //default run time
if(Math.random()>0.5){ timeout=1000; } // special run time (50/50 in this demo)
setTimeout(workload, timeout);
//do normal workload:
console.log(callback, timeout);
} // end workload
// use any time for first run:
setTimeout(workload, 12345);
you can also use a "static property" to externally adjust the timer:
function workload(callback) {
setTimeout(workload, workload.timeout || 5000); //default to 0.2hz
//do normal workload:
console.log(callback, workload.timeout);
} // end workload
// use any time for first run:
setTimeout(workload, 2000);
workload.timeout=1000; // change to poll at 1hz;
Note that I didn't actually implement the callback, and without bind() the argument will be empty each execution. because the function itself is basically the callback, you don't need one. You could easily turn one of these patterns into a factory where you pass it a workload function, a default interval, an initial delay, and another conditional evaluator function for ultimate flexibility.
I have encountered following issue when creating simple task: displaying html clock by using WebKit engine. Additional requirement were to handle system time change and that it should work on Windows.
I have used setInterval to achive this but it seems to freeze browser after I change system time backward.
For me it looks like WebKit issue. It is easy to reproduce on safari by running this simple code:
<p id="date"></p>
setInterval(SetTime, 1000);
function SetTime() {
document.getElementById('date').textContent=new Date();
}
After that I have made another approach with recursive setTimeout call. Same effect.
(function loop() {
document.getElementById('date').textContent=new Date();
setTimeout(loop, 1000);
})();
Any ideas why is that happening and how to go around this?
This is almost definitely an issue with WebKit.
The Problem
When you use setTimeout, you create a 'timer' with two properties:
A timestamp, set to now + the specified delay
A callback to fire once once the system time is greater than the timestamp.
You can imagine a naïve implementation of setTimeout looking something like this:
var timers = [];
function setTimeout(callback, delay) {
var id = timers.length;
timers[id] = {
callback: callback,
timestamp: Date.now() + delay
}
return id;
}
This would simply create a timer and add it to a list. Then, on each tick, the JS runtime would check these timers and execute the callbacks for those that have fired:
var now = Date.now();
for(var id in timers) {
var timer = timers[id];
if(timer && timer.timestamp < now) {
callback();
delete timers[id];
}
}
Given this implementation, imagine now changing the system time (i.e. Date.now() in the examples above) to a value in the past -- the timer's timestamp will still be set relative to the previous system time (i.e. in the future).
The same issue exists with setInterval, which (assuming sane code in WebKit) will be implemented using setTimeout.
Unfortunately, this means that any invocation of setTimeout or setInterval is going to suffer.
The Solution
As an alternative, you can use the lovely window.requestAnimationFrame method to perform a callback on each tick. I haven't tested this at at all, but it should continue to fire on each tick, regardless of the system time.
As a bonus, each time it fires the callback, you get passed the current timestamp as a parameter. By keeping track of the previous timestamp passed to your callback, you could easily detect backwards system time changes:
var lastTimestamp;
var onNextFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame;
var checkForPast = function(timestamp) {
if(lastTimestamp && timestamp < lastTimestamp) {
console.error('System time moved into the past! I should probably handle this');
}
lastTimestamp = timestamp;
onNextFrame(checkForPast);
};
onNextFrame(checkForPast);
Conclusions
This might not be great news for you, but you should probably rewrite your entire application to use requestAnimationFrame anyway - it seems much more suited to your needs:
var onNextFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame;
var dateElem = document.getElementById('date');
var updateDate = function(timestamp) {
dateElem.textContent = new Date();
onNextFrame(updateDate);
};
onNextFrame(updateDate);