Why setTimeout calls make different result - javascript

I have next code
setTimeout(function() {
setTimeout(function() {
console.log('foo');
}, 50);
}, 100);
setTimeout(function() {
setTimeout(function() {
console.log('baz');
}, 100);
}, 50);
The question was what's the output. But on running code I got different results on multiple runs - sometimes it's foo baz, sometime it's baz foo.
So there is two questions:
1) why I have different results?
2) Why sometimes I got baz foo ?
P.S. There is code snippet, but with code snippet I always get the same result
P.P.S. If it's environment specific - I use Chrome ( and FF ), but questions still actual
P.P.S. Possible answer was about usage console.log, but for
var a = [];
setTimeout(function() {
setTimeout(function() {
a.push('foo');
}, 50);
}, 100);
setTimeout(function() {
setTimeout(function() {
a.push('baz');
}, 100);
}, 50);
setTimeout(function() { console.log(a); }, 300);
it's still actual

The timeout specified is a minimum time that the browser should wait before executing the function, not a guaranteed time. If the browser is busy doing other things when the timer goes off, the function will be delayed.
So when you schedule the timer for 50 ms, it might not actually run until 53 ms later. Then it will set another timer for 100 ms after that, which is 153 ms after you started. Meanwhile, the timer that's set for 100 ms could run in 101 ms, and then set its second timer for 50 ms later, which is 151 ms after everything started. In this example, it will print foo bar.
Or you could get different delays, and the result would be bar foo.
If you need to perform actions in a specific sequence, you should run them sequentially in a single function, or call the second one from a callback of the first, or use promises in a specific order. Depending on precise millisecond timing with setTimeout is not reliable.

setTimeout doesn't schedule things after the EXACT time you specify - its a an approximation that is used by the javascript engine to schedule your functions as close as possible to the time you specify. In general, you shouldn't rely on timeouts to guarantee the order of execution. Assume that your timeouts can fall within a range of time, and don't expect the specified time to be the exact time that your functions will run.
Read here for more info.

Welcome to the world of asynchronous/event driven programming!
One of key things to understand about timers in javascript (and general purpose timing functions in nearly all languages) is that they are not designed to be precise to the tick. What occurs instead is that the program tells the operating system/js engine to "hey, send me a notification when at least this much time has elapsed." The operating system/js engine, however, may have hundreds, thousands, or even millions of tasks it needs to prioritize and execute, so it can't spend all of it's time just watching the clock waiting to fire off that notification. So, to save processing power, keeps all of these timing events in a queue, and only periodically checks to see how much time has gone by and if the events have expired.
In your particular case, you have an timeout event being created as a result of a timeout event being fired. So if the initial event is delayed slightly, that pushes back start time and thus the expiration of the second event. In your foo/baz example, if the initial foo timeout is delayed but the initial baz is not, then the baz callback will be added to the event queue before the foo callback is, and you get "baz foo".
Or sometimes baz will get delayed and foo won't, or sometimes neither will, or sometimes they both will. There's just too much going on under the hood (maybe not even related to your script/code/program) to be able to predict or rely on the exact execution order. That's the takeaway, and it's a good policy to live by for basically all of event driven programming.

Related

SetInterval / Async Await oddity

Consider the two functions below, both async, one a brutal workload that takes a lot of time, and the other one a wait function that waits a precise number of seconds by setting a timeout.
async function Brutal_Workload()
{
for(var x = 0; x< 1000 * 1000 * 1000; x++)
{
}
}
async function Time_Wait(seconds)
{
var promise = new Promise((resolve, reject) =>
{
var msecs = Math.floor(seconds * 1000);
var timer =
setTimeout(
function()
{
clearTimeout(timer);
resolve();
},
msecs);
});
return promise;
}
Now, let's call the first function in a setInterval cycle
setInterval(
async function()
{
await Brutal_Workload();
console.log("BLIP");
}, 1000 / 30);
All as intended: despite the interval running at 30 calls per second, I only get 1 blip per second, because Brutal_Workload is choking it.
But when I use the other function...
setInterval(
async function()
{
await Time_Wait(1);
console.log("BLIP");
}, 1000 / 30);
I get 30 BLIPs per second.
The Time_Wait function, which works otherwise just fine outside of setInterval, doesn't seem to work here.
Any idea of what might cause this behavior?
Ok, rather than continue the back-and-forth in the comments, I'm just going to post this as an answer.
Javascript is both single-threaded and concurrent. I know you know this, but you don't seem to realize the implications. In your first function, you only see a console.log every so often, because your "brutal workload" blocks the only thread of execution until it completes, which means that regardless of what number you passed to setInterval not only is no other invocation running, the next bit of work isn't even being queued to run because your brutal workload is blocking the only thread of execution.
Understand, the runtime environment's setInterval runs on the same (only) thread as your code, the JS engine doesn't cheat and run your stuff in one thread and setInterval in another. So while brutal workload is doing its thing, setInterval itself, much less the function you passed to it, is not running at all. Using async and wrapping your brutal workload in a Promise makes essentially zero difference in terms of our discussion here, because brutal workload dominates.
So that explains the first example, so far so good. On to the second.
Unlike the first example, in the second there is no long-running chunk of code to tie up the thread of execution. So your callback to setInterval runs, dutifully registers a thing to run in a second, and yields control of the thread of execution, something that again the first example does not (and cannot do). Here the Promise and async/await actually does enable concurrency which it can't do in the first example because brutal workload is hogging the thread. So in a fraction of a second your callback to setInterval runs again, dutifully queues up another thing to run after a second has passed, and so on.
So after ~1 second that first queued up log happens, and then after a fraction of a second after that the second, and then so on. This doesn't happen in the first example because although you told setInterval to run 30x/sec brutal workload means that setInterval itself can't run to even queue your callback to be ran.

Allow running setInterval more than once per millisecond in nodejs

I have a node script which is supposed to utilize all the CPU resources a single node process could get. But I found setInterval to be too slow.
And sure enough I found this in the documentation:
When delay is larger than 2147483647 or less than 1, the delay will be
set to 1.
source: https://nodejs.org/api/timers.html#timers_setinterval_callback_delay_args
Now I wonder if there is a way to reduce the limit further or if there is an alternative function that I could use.
I can't just use a normal loop because there are other asynchronous things that need to run at the same time.
Edit:
Again: I can't just use a normal loop because there are other asynchronous things that need to run at the same time.
I'm not sure why this is so hard to understand.
While a normal loop is running, you are blocking the execution of everything else. It doesn't matter if you put the loop in another asynchronously executed function.
What does this mean?
Let's look at some examples:
setInterval(()=>{console.log('a')},1000) // asynchronous thing that needs to run in the background
while (true) {
// do whatever
}
What will this code do? It will block everything. console.log('a') will not be executed continuously.
setInterval(()=>{console.log('a')},1000) // asynchronous thing that needs to run in the background
setTimeout(()=>{
while (true) {
// do whatever
}
}, 1)
This will also block the execution of the intervals as soon as the while loop starts.
I believe the question belongs to node rather than to browser. You can use some of the following options (recursively/in loop) for reducing your delay time.
setImmediate
setImmediate - Schedules the "immediate" execution of the callback after I/O events' callbacks. Returns an Immediate for use with clearImmediate().
When multiple calls to setImmediate() are made, the callback functions are queued for execution in the order in which they are created. The entire callback queue is processed every event loop iteration. If an immediate timer is queued from inside an executing callback, that timer will not be triggered until the next event loop iteration.
It's from node guides:
setImmediate and setTimeout are similar, but behave in different
ways depending on when they are called.
setImmediate() is designed to execute a script once the current poll phase completes.
setTimeout() schedules a script to be run after a minimum threshold in ms has elapsed.
process.nextTick
The process.nextTick() method adds the callback to the "next tick
queue". Once the current turn of the event loop turn runs to
completion, all callbacks currently in the next tick queue will be
called.
From node guide
We recommend developers use setImmediate() in all cases because it's
easier to reason about (and it leads to code that's compatible with a
wider variety of environments, like browser JS.)
Thanks to Josh Lin for the idea to just run multiple intervals. I ended up with two simple wrapper functions for setInterval and clearInterval:
function setInterval2(cb,delay) {
if (delay >= 1)
return [setInterval(cb,delay)];
var intervalArr = [];
var intervalCount = Math.round(1/delay);
for (var i=0; i<intervalCount; i++)
intervalArr.push(setInterval(cb,1));
return intervalArr
}
function clearInterval2(intervalArr) {
intervalArr.forEach(clearInterval);
}
It works just like the original functions:
var count = 0;
// run interval every 0.01 milliseconds:
var foo = setInterval2(function(){
count++;
},0.01);
// stop execution:
clearInterval2(foo)
1 setInterval multiple times run more!
let count = 0,
by = 100,
_intervals = [],
timelimit = 100
for (let i = 0; i < by; i++) {
_intervals[i] = setInterval(() => count++, 1)
}
setTimeout(() => {
_intervals.forEach(x => clearInterval(x))
console.log(`count:${count}`)
}, timelimit)
2.setTimeout recurser run less!
let count = 0,
go = true
recurser()
setTimeout(() => {
go = false
console.log(`count:${count}`)
}, 100)
function recurser() {
count++
go && setTimeout(recurser)
}
3.requestAnimationFrame run less!
let count = 0,
go = true,
timelimit = 100
step()
setTimeout(() => {
go = false,
console.log(`count:${count}`)
}, timelimit)
function step() {
count++
go && requestAnimationFrame(step)
}
so as I know ,run setInterval multiple times, and I believe while will count more
You ask if it is possible to
run setInterval more than once per millisecond in nodejs
As you note in your question, this is not possible with setInterval, since there is always a minimum delay of at least 1 ms in node.js. In browsers, there is often a minimum delay of at least 10 ms.
However, what you want to achieve—to repeatedly run CPU-intensive code without unnecessary delay—is possible in other ways.
As noted in the answer by The Reason, setImmediate is a good option available in node.js. As setImmediate has limited browser support, and is unlikely to be widely supported in the future, there is another approach that also works in browsers.
While browsers enforce a minimum delay for setInterval and setTimeout, the delay for setTimeout is enforced from when the timer is set, not when it is run. If we use setTimeout repeatedly to call CPU-intensive code, we can make sure that a timer is always set 10–15 ms in advance (if the code takes at least 10–15 ms to run), thus reducing the actual delay to 0 ms.
The demo snippet below borrows code from this answer to demonstrate how the use of timers set in advance may make the delay smaller than what is enforced. In the browsers I tested, this usually results in a 0 ms delay.
// First: repeat runCPUForAtLeast50ms() 10 times
// with standard repeated setTimeouts and enforced delays
testTimeout(10, function(){
// Then: repeat runCPUForAtLeast50ms() 10 times
// using a repeated set of queued setTimeouts
// circumventing the enforced delays
testTimeout(10, false, true);
});
function testTimeout(repetitions, next, multiple) {
var delays = [];
var lastCheck;
var extraTimers;
function runner() {
if(lastCheck){
delays.push((+new Date) - lastCheck);
}
if(repetitions > 0) {
//process chunk
runCPUForAtLeast50ms();
//set new timer
setTimeout(runner);
} else if(repetitions === 0) {
//report result to console
console.log((multiple?
'Repeated multiple timers delays: ' :
'Repeated single timer delays: ') + delays.join(', '));
//invoke next() function if provided
next && next();
}
repetitions--;
lastCheck = +new Date;
}
setTimeout(runner);
if(multiple){
// make sure that there are always a fixed
// number of timers queued by setting extra timers
// at start
extraTimers = 10;
while(extraTimers--)
setTimeout(runner);
}
}
function runCPUForAtLeast50ms() {
var d = (+new Date) + 50;
while(+new Date < d);
}
I think you can solve your problem using async module... a way could be:
async.parallel([
(callback) => {
// do normal stuff
},
(callback) => {
// do your loop
}
], (err, results) => {
// ...
});
But take into account this note from the official documentation...
Note: parallel is about kicking-off I/O tasks in parallel, not about
parallel execution of code. If your tasks do not use any timers or
perform any I/O, they will actually be executed in series. Any
synchronous setup sections for each task will happen one after the
other. JavaScript remains single-threaded.
In short answer, you can't. There are some limitation of Javascript/Node as it is a single thread application. That's why you have async interrupts.
The long answer:
From the computer architecture's perspective, modern CPU and Kernel scheduling is not deterministic. If you want such fine grain control, I would suggest you look at MCU and embedded solutions that does not have a kernel scheduler. Because, your OS have many other processes and Kernel processes that takes up CPU time, so kernel scheduler have to keep scheduling different processes to be run on the CPU and meet many different demands.
Even with the set 1ms, when you try to measure, it is probably not 1ms (exact time depends on OS, hardware and amount of processes running on your computer).
Now, if you want to use all CPU resources, not possible.
But if you want to utilize as much as resources as possible, you can explore current programming pattern. For example, you can schedule 1 million threads (you machine probably won't be able to handle it), or some crazy large amount of processes and let your scheduler to be constantly putting process on your CPU, so there is no idle time and max out CPU utilization.
Alternatively, you can run CPU Stress tests, and those are designed to simply max out your CPU and keep it burning to high temperature -- make sure you have the cooling solution in place.

Creating a cron job using a while loop

There are several libraries (especially for NodeJS and Javascript) that allow you to implement cron jobs and subsequently host them on a server.
In essence, cron jobs seem to me nothing more than repetitive tasks that are executed at a specific time/date on a day.
I was wondering therefore what the difference is between these libraries and just let's say a custom while loop. For instance in Javascript we could write:
var keepRunning = true
while (keepRunning) {
setTimeout(function () {
// call function to be executed when time constraint satisfied
}, 5000);
}
My questions are therefore:
why do we use cron job libraries? What are the benefits above a custom function like above?
This would not work as you might expect:
var keepRunning = true
while (keepRunning) {
setTimeout(function () {
// call function to be executed when time constraint satisfied
}, 5000);
}
That code will schedule new setTimeout callbacks as fast as it can while keepRuning is true, never unwinding the call stack and letting the event loop run any of those callbacks. It will likely consume all of your memory without running the scheduled code even once.
What you can do is something like this:
var keepRunning = true;
function run() {
if (keepRunning) {
// call function to be executed when time constraint satisfied
setTimeout(run, 5000);
}
}
setTimeout(run, 5000);
If you want to schedule all the callbacks at once, then you might do something like this:
for (let i = 1; i <= 100; i++) {
setTimeout(function () {
// call function to be executed when time constraint satisfied
}, 5000 * i);
}
but in this example you need to multiply the timeout by the iteration variable to make sure that they are not scheduled to run at the same time - i.e. they are still scheduled all at once but they are later run at different times.
Remember that JavaScript runs to completion and callbacks are executed later when the call stack unwinds. It's also important that for and while loops block the event loop from executing and no event can be handled while the loop is running.
Cron handles very time specific events far better than this. If you wanted something to happen at 9am each day you would absolutely have to use Cron over some method like this.
Cron measures time from epoch and is the most accurate way of scheduling tasks. I would also imagine it would result in better performance than what you are suggesting.
Why would you NOT use Cron?
A library is a collection of useful code. Those collections tend to group up a significant amount of functions, objects, etc.
Your example was just one situation that had very little versatility. Libraries would provide much more options for your loop, and would go beyond just addressing the rate, but also other factors (depending on what specific library you are referring to).

NodeJs setInterval without extending process life time

I simplified it to better understand what I need: The task that I have to do is, that we have a long unknown nodejs process (with a lot of queued async functions where we never know when they are finished or something like that) and we want to have an update process, that we store current process state in database. For that we have a start up (it stores "start") and a end process that is on top of process.on('beforeExit', function () { ... });. Now we have to handle the "still in running" process that is requested by our customer. For that we want to update the state every ten minutes to running with timestamp (this function already exists and is called state.setRunningState()
Now I have the problem how can I trigger that function every ten minutes. For that I was going the approach to trigger on each event of the working process this function and compares if it is older then 10 minutes ago. Problem is: Some times there are much more time without any event. So second option is setInterval() and here is what my question is about: If I use setInterval my nodejs process will never reach an end, so the process will run endless until Interval is cleared. But I also do never know when I should call clearInterval()
So the Question is: Is there a way to create such a timeout without extending the life time of the nodejs process. If everything is done it should end and ignore the rest of the interval.
Contrary to some of the comments here, this is not a strange requirement to have something executed periodically while the process is running without making the process run infinitely which would make it quite pointless.
There is a built-in mechanism for that. If you don't want your interval (or timeout) to stop the process from exiting then you need to use the .unref() method.
Instead of:
setInterval(() => {
console.log('Interval');
}, 1000);
use:
setInterval(() => {
console.log('Interval');
}, 1000).unref();
and your interval will not stop the process from exiting if there are no other events pending.
Try running this example:
setInterval(() => {
console.log('Interval');
}, 1000).unref();
setTimeout(() => {
console.log('Timeout 1');
}, 3000);
setTimeout(() => {
console.log('Timeout 2');
}, 5000);
See the docs:
https://nodejs.org/api/timers.html#timers_timeout_unref
Let me see if I get this straight.
1- You want to trigger an event every x mins unless if the existing process has ended?
2- You say that node would not quit the process as long as there is a running set interval.
3- you say that since your process runs " lot of queued async functions" you cannot know when the process should end
I think the simplest solution would be to just set another interval to run at a higher frequency and to clear the interval if all functions have returned. Otherwise you might be interested in reading about webworkers
https://www.npmjs.com/package/webworker-threads

understanding execution of setTimeout() functions that follow one another

I need to execute multiple functions one after another in fixed time intervals, thus using setTimeout. I want to ensure that I understand how it executes. I have following logic:
setTimeout(function() {
//Execute first function
}, 200);
setTimeout(function() {
//Execute second function
}, 400);
setTimeout(function() {
//Execute third function
}, 600);
Does this mean that first function executes after 200ms, second one 200ms after the first, and the third one 200ms after the second and so on? Or do I need to change something.
Does this mean that first function execute after 200ms, second one 200ms after first and third one 200ms after second and so on?
Essentially, yes that's what it means. Bear in mind however that the specification only guarantees that the delay parameter is a minimum time that must be awaited, and browsers can and do throttle these calls sometimes - notably if the tab is not active:
Note: This API does not guarantee that timers will fire exactly on schedule. Delays due to CPU load, other tasks, etc, are to be expected.
and:
Optionally, wait a further user-agent defined length of time.
Note: This is intended to allow user agents to pad timeouts as needed to optimise the power usage of the device. For example, some processors have a low-power mode where the granularity of timers is reduced; on such platforms, user agents can slow timers down to fit this schedule instead of requiring the processor to use the more accurate mode with its associated higher power usage.
Also, if any of your functions take a noticeable amount of time to run, the delay between the end of one function finishing and the next starting may not be 200ms - it could be less.
Following James' answer, in order to guarantee this minimum delay, you should trigger the next setTimeout() inside the anonymous callback, each of them with the 200ms delay specified:
setTimeout(function() {
//Execute first function
setTimeout(function() {
//Execute second function
setTimeout(function() {
//Execute third function
}, 200);
}, 200);
}, 200);
This way you can be sure that the delay between each function will be at least 200ms

Categories

Resources