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.
Related
Here is the code I'm running:
async function sleep(ms) {
const start = new Date();
while (new Date() - start < ms) { };
}
const start = new Date();
sleep(5000).then(() => console.log("1!"));
console.log(new Date() - start, "ms");
sleep(5000).then(() => console.log("2!"));
console.log(new Date() - start, "ms");
The output I would expect is this:
1 ms (or some other small number of ms)
2 ms (or some other small number of ms)
1!
2!
Instead what I see is this:
5000 ms
10005 ms
1!
2!
I'm a bit confused by this. Firstly, why are the two sleep functions not running asynchronously? Why doesn't the second call to sleep start until the first one is finished?
Secondly, if the second call doesn't start until the first is completed, why is 1! printed before 2!?
If I change the sleep(ms) function to the following, which was suggested in another StackOverflow question, the code works as expected:
function sleep(ms) {
return new Promise(res => setTimeout(res, ms));
}
If I replace sleep(ms) with some slow computation without using a timeout, what should I expect?
JavaScript isn't really multithreaded. It relies on two things to give that illusion:
Computers are really really fast and generally complete whatever needs to be done instantaneously as far as a human can tell
Because they are fast and the world is slow, computers spend a lot of time waiting for something to happen, and can profitably do something else in the meantime
Basically, JavaScript runs a thread until it either finishes, or is waiting for something to happen (e.g. an async network call), at which point JavaScript will switch to another thread, if there is one.
Your first sleep() function is a busy wait. It consumes 100% CPU doing nothing. More importantly, it never gives another thread a chance to run. The promise solution does it the JavaScript way: it ends almost immediately (thereby giving other threads a chance to run) and uses SetTimeout to regain control (in an async sort of way) when other threads aren't running.
The reason why the functions marked as async are not run concurrently with other code is that async does not cause a function to be asynchronous (!). Instead, this keyword marks a function as returning a Promise, and also enables some syntax sugar such as await.
This means that async has absolutely nothing to do with Threads, Tasks, or any other concurrency primitives known from other languages. In a JavaScript program, all visible code is executed in a single thread in a blocking fashion, and it runs to completion. This is why the long while loop blocks program flow.
Why does setTimeout work as expected? Because the code that actually runs is setTimeout and the res callback, nothing more. In the background, the event loop ensures that res is called eventually, but the machinery that handles this is hidden from the developer.
Let's look in depth at the first case.
What happens, step by step, is this - note that user code runs to completion in an uninterrupted fashion:
The first sleep() runs to completion, and its return value's .then() method is called, which enqueues a callback as a so-called microtask (which will log 1!) for the event loop to execute soon
The first console.log runs
The second sleep() runs to completion, and its return value's .then() method is called, which in turn enqueues another microtask
The second console.log runs
<The user program is now finished, but there is stuff in the event loop for the JS engine to process!>
The event loop processes the first microtask: () => console.log("1!")
The event loop processes the second microtask: () => console.log("2!")
<The event loop is now empty - execution is ended>
If you replace the body of the sleep() function with setTimeout, you'll notice that setTimeout itself is quick to execute - all it does is enqueue something for the event loop to process later and return. This is why the flow of execution is not blocked.
What would be the result if the callback function is not completed before the timeout of the setInterval function.
For example:
setInterval(function() {
// This block takes more than 5 seconds.
}, 4000);
Now the setInterval has a timemout of 4 seconds whereas the callback functions takes 5 seconds to complete. What would happend, would it wait for the function to complete or make execute the callback again in 4 seconds?
It will wait for the callback to complete, as JavaScript is single-threaded. If you run the below snippet, you will see that 'done' is printed every 5 seconds.
setInterval(function() {
let curr = new Date;
while(new Date() - curr <= 5000);
console.log('done');
}, 4000);
It depends.
If you put there some computations that happens to take 5 seconds (like looking for prime numbers or something), you'll lock the main thread and another call would be done only when it's unlocked, so in that case after about 5 seconds.
If the part that takes so long is for example a http request it will call the function every 4 seconds as it should. As far as I know there is no mechanism in setInterval that would check if function's promise is done or not.
So your setInterval has 2 parameters, a callback and the duration (4s)
There are a few things than can affect your interval:
your setInteval call a browser API which will start a timer to exactly 4 seconds. Once the timer triggers that 4 seconds, it will append your callback on the JS callback queue. Again, this happens exactly after 4s.
Once all the synchronous code will be executed, JS will start running the callbacks in the callback queue, one at a time.
To answer your question: if it's just the code that you posted, it will most likely take exactly 4 seconds. In case you have some heavy operation in your code that takes more than 4 seconds, that code may take longer since it will run only after.
Because of the event loop, the task queue and the single-threaded nature of JavaScript, it would always wait for the function to complete. Synchronous code is never canceled, unless the script is forcefully stopped.
The HTML standard says that timers must:
Wait until any invocations of [the timer initialization algorithm] that had the same method context, that started before this one, and whose timeout is equal to or less than this one's, have completed.
Other timers and browser/runtime tasks would also run between the function. But if the function is running on the main thread, the program would only receive events while the function is not running. In a browser, this would mean that the website would not be interactive for most on the time.
For those reasons, such functions with heavy synchronous computations should be run inside a Worker or split among several tasks (see How to queue a task in JavaScript?).
(I'm assuming "This block takes more than 5 seconds." means that the function returns after 5 seconds.)
Check this out I found my own answer.
What this does is, it spawns a thread to execute the callback function after every timeout that works seperately.
document.write('Part 1:<br>');
setInterval(function() {
var x = Date.now();
document.write(x + '<br>');
setTimeout(function() {
var y = Date.now();
document.write(y.toString() + ' : ' + (y-x).toString() + '<br>');
}, 5000);
}, 2000);
I need to execute an operation that needs to be executed relatively fast (let's say 10 times per second. It should be fast enough, but I can sacrifice speed if there are issues.) This is an ajax request, so potentially I do not know how much time it takes - it could even take seconds if network is bad.
The usual:
setInterval(() => operation(), 100);
Will not work here, because if the network is bad and my operation takes more than 100 ms, It might be scheduled one after another, occupying JS engine time (please correct me if I'm wrong)
The other possible solution is to recursively run it:
function execute() {
operation();
setTimeout(execute, 100);
}
This means that there will be 100 ms between the calls to operation(), which is OK for me. The problem with this is that I'm afraid that it will fail at some point because of stack overflow. Consider this code:
i = 0;
function test() { if (i % 1000 == 0) console.log(i); i++; test(); }
If I run it my console, this fails in around 12000 calls. if I add setTimeout in the end, this would mean 12000 / 10 / 60 = 20 minutes, potentially ruining the user experience.
Are there any simple ways how to do this and be sure it can run for days?
There's no "recursion" in asynchronous JavaScript. The synchronous code (the test function) fails because each call occupies some space in the call stack, and when it reaches the maximum size, further function calls throw an error.
However, asynchrony goes beyond the stack: when you call setTimeout, for example, it queues its callback in the event loop and returns immediately. Then, the code, that called it can return as well, and so on until the call stack is empty. setTimeout fires only after that.
The code queued by setTimeout then repeats the process, so no calls accumulate in the call stack.
Therefore, "recursive" setTimeout is a good solution to your problem.
Check this example (I recommend you to open it in fullscreen mode or watch it in the browser console):
Synchronous example:
function synchronousRecursion(i){
if(i % 5000 === 0) console.log('synchronous', i)
synchronousRecursion(i+1);
//The function cannot continue or return, waiting for the recursive call
//Further code won't be executed because of the error
console.log('This will never be evaluated')
}
try{
synchronousRecursion(1)
}catch(e){
console.error('Note that the stack accumuates (contains the function many times)', e.stack)
}
/* Just to make console fill the available space */
.as-console-wrapper{max-height: 100% !important;}
Asynchronous example:
function asynchronousRecursion(i){
console.log('asynchronous',i)
console.log('Note that the stack does not accumuate (always contains a single item)', new Error('Stack trace:').stack)
setTimeout(asynchronousRecursion, 100, i+1);
//setTimeout returns immediately, so code may continue
console.log('This will be evaluated before the timeout fires')
//<-- asynchronusRecursion can return here
}
asynchronousRecursion(1)
/* Just to make console fill the available space */
.as-console-wrapper{max-height: 100% !important;}
The two alternatives you showed here actually share the flaw you're concerned about, which is that the callbacks might bunch up and run together. Using setTimeout like this is (for your purposes) identical to calling setInterval (except for some small subtleties that don't apply with a light call like making an AJAX request.)
It sounds like you might want to guarantee that the callbacks run in order, or potentially that if multiple callbacks come in at once, that only the most recent one is run.
To build a service that runs the most recent callback, consider a setup like this:
let lastCallbackOriginTime = 0;
setInterval(()=>{
const now = new Date().getTime();
fetch(url).then(x=>x.json()).then(res=>{
if ( now > lastCallbackOriginTime ) {
// do interesting stuff
lastCallbackOriginTime = now;
}
else console.log('Already ran a more recent callback');
});
}, 100);
Or let's make it run the callbacks in order. To do this, just make each callback depend on a promise returned by the previous one.
let promises = [Promise.resolve(true)];
setInterval(()=>{
const promise = new Promise((resolve, reject)=> {
fetch(url).then(x=>x.json()).then(serviceResponse=>{
const lastPromise = promises[promises.length - 1];
lastPromise.then(()=>resolve(serviceResponse));
}).then((serviceResponse)=>{
// Your actual callback code
});
promises.push(promise)
});
}, 100);
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.
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.