Why requestAniamtionFrame doesn't cause stack overflow error? - javascript

I am trying to understand what happens under the hood of the browser when requestAnimationFrame() is called recursively.
I have ran code like this in my browser console:
function foo(){
requestAnimationFrame(foo);
console.log("foo");
}
foo()
The result: "foo" is being printend out non-stop.
My problem: I cannot figure out how I am not exceeding allowed stack size.
What I think is happening:
function callAsynchronously(callback){
setTimeout(callback, 1);
}
function foobar(){
callAsynchronously(foobar); // replacement for requestAnimationFrame
console.log("hi");
}
foobar() // result is the same as before, non-stop printing
Above code is how I am visualizing requestAnimationFrame:
foobar() is put on the stack
callAsynchronously(foobar) is put on stack
callAsynchronously(foobar) popped from the stack
console.log("hi") is put on stack / browser apis put foobar callback into some queue after setTimeout is finished
console.log("hi") is popped from the stack
browser sees empty stack and puts callback from the queue on the stack
Repeat
I assume that requestAnimationFrame does something similar to not exceed allowed stack size but I am not sure if that's all there is to it. Also does it mean that I can bombard browser apis with async callbacks without getting any errors as long as I keep my stack size within acceptable range?

requestAnimationFrame doesn't run until all synchronous execution has completed. It schedules the given callback. It acts very much like setTimeout. Its not truly recursive, it just seems that way. Thats the nature of the event loop.

requestAnimationFrame is called according to the refresh rate of the device screen. For example if you are viewing on 60hz screen the foo function will be called 60 times.

Related

Clarification on how asynchronous functions queue with each other [duplicate]

I was in an awkward situation,
I am working with pure JavaScript for almost 3 years, and I know that JavaScript is single-threaded language,
and that you can simulate asynchronous execution using setInterval and setTimeout functions,
but when I thought about how they can work I couldn't clearly understand it.
So how these functions affect execution context?
I suppose that in specific time runs only one part of the code and after it switches to
another part. If so, then would a lot of setInterval or setTimeout
calls affect performance?
Javascript is singled-threaded but the browser is not. The browser has at least three threads: Javascript engine thread, UI thread, and timing thread, where the timing of setTimeout and setInterval are done by the timing thread.
When calling setTimeout or setInterval, a timer thread in the browser starts counting down and when time up puts the callback function in javascript thread's execution stack. The callback function is not executed before other functions above it in the stack finishes. So if there are other time-consuming functions being executed when time up, the callback of setTimeout will not finish in time.
How setTimeout / setInterval work's in JavaScript
Browser has API for Timer function just like API for event ex.
'click'
'scroll'
Assume that you have following code in your application
function listener(){
...
}
setTimeout(listener, 300)
function foo(){
for(var i = 0; i < 10000; i++){
console.log(i)
}
}
foo()
![See How Function Execution work's in javascript ][1]
[1]: https://i.stack.imgur.com/j6M6b.png
At this point as per our code we wrote above our call stack will look like
Call Stack -> foo
And let's assume that foo will take 1s to complete it's execution, as we already defined 1 timeout in our code and we are running it before "foo" complete's it's execution i.e at 300ms
What will happen then ?
Does javascript stop executing foo and start executing setTimeout ?
No
As we already know javascript is single threaded so it has to complete execution of foo before moving ahead, but how does browser ensure that after execution of foo the "setTimeout" will execute ?
Here javascript magic comes into picture
When 300ms is expired, the browser's "Timer API" kicks in and put the timeout handler into "Message Queue".
At this point "Message Queue" in above image will look like
Message Queue -> setTimout:listner
And
Call Stack -> foo
And when "Call Stack" becomes empty i.e foo completes it's execution the "Event Loop" as shown in the image will take the message from message queue and push it into stack
The only job of "Event Loop" is when "Call Stack" becomes empty and "Message Queue" has entry in it then dequeue the message form "Message Queue" and push it into "Call Stack"
At this point Message Queue in above image will look like
Message Queue ->
And
Call Stack -> listener
And that's how setTimeout and setInterval works, even though we specify 300 ms in the setTimeout it will execute after "foo" completes it's execution in this case i.e after 1s.
And that's why timer specified in setTimeout/setInterval indicates "Minimum Time" delay for execution of function.
Javascript is single threaded but browser is not.
There is 1 stack where function and statements get executed.
there is 1 queue where function are queued to be executed.
there are web APIs which can hold the function for particular time, defined in setTimeout and setInterval in event table.
when javascript engine execute js file line by line, if it finds a line as statement or function call it load it on stack and execute but if it is setTimeout or setInterval call,
then function handler associated with setTimeout or setInterval is taken out by TIME API (one of web API of browser)and hold it for that time.
Once this time is over, Time Api put that function at end of execution queue.
Now Execution of that function depends on other functions calls which are ahead of in queue.
Note: this function call is called upon window object.
setTimeout(function () {console.log(this)}, 300)
Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
JavaScript is a single-threaded scripting language, so it can execute one piece of code at a time (due to its single-threaded nature) each of these blocks of code is “blocking” the progress of other asynchronous events. This means that when an asynchronous event occurs (like a mouse click, a timer firing, or an XMLHttpRequest completing) it gets queued up to be executed later.
setTimeout()
when you use setTimeout() it will execute only when its turn comes in a queue, if an earlier event (of setTimeout) blocks due to some reason setTimeout can be delayed than the specified time in setTimeout() function. during the execution of setTimeout callback function, if any event occurs(e.g click event),it gets queued up to be executed later.
setTimeout(function(){
/* Some long block of code... */
setTimeout(arguments.callee, 10);
}, 10);
setInterval(function(){
/* Some long block of code... */
}, 10);
setInterval()
Similar to setTimeout but continually calls the function (with a
delay every time) until it is canceled.
setTimeout code will always have at least a 10ms delay after the
previous callback execution (it may end up being more, but never
less) whereas the setInterval will attempt to execute a callback
every 10ms regardless of when the last callback was executed.
If a timer is blocked from immediately executing it will be delayed
until the next possible point of execution (which will be longer than
the desired delay). Intervals may execute back-to-back with no delay
if they take long enough to execute (longer than the specified
delay).
Just a note in regards to my experience, If you are going to use setTimeout(), the function will always be delayed (and I mean executed later) or executed after further code which is not 'timeouted'. This may happen even with functions which have delay = 0 and is caused by Event Loop.
See example below:
setTimeout(function() {
console.log('Second');
}, 0)
console.log('First');

Recursion in js setTimeout how it work? and why it work?

function printNumbers(from, to) {
let current = from;
function go() {
alert(current);
if (current < to) {
setTimeOut(go, 1000); //recursion to function go()
}
current++; // because of recursion execution should not reach this point
}, 1000);
}
printNumbers(5, 10);
Please explain to me why ^current++^ works immediately? but because of recursion it should not work. isnt it? please explain me who understand how it work and why
setTimeout is not blocking. It puts a function on a queue to be called when some time has passed. The rest of the function still executes without pause.
There is no return statement or anything else that would stop the JS engine from reaching the current++; statement.
To supplement Quentin's answer, this setTimeout(go, 1000) line (FYI, setTimeout is the proper spelling, not setTimeOut) isn't actually doing any recursion. It's passing off a function go to be called after 1000 ms in the event loop after the stack empties (the same stack that can do recursion and overflow). It's incidental that this all happens within the same function that's passed as a parameter to the timeout which makes it visually look recursive.
What happens is the setTimeout line runs and adds the function go to the event loop and guarantees a delay of at least 1000 ms. Then, the rest of the synchronous code runs, including the rest of go and current++;. Later on, when the stack is empty, tasks on the loop are executed in order, including go (assuming the 1000 ms timer has elapsed).
This explains why code like:
(function run() {
requestAnimationFrame(run);
// do stuff
})();
never overflows the stack: it's not actually recursion and each call frame is destroyed before the next call happens.
As an aside, it may be surprising that
(function run() {
requestAnimationFrame(run);
// do stuff
})();
and
(function run() {
// do stuff
requestAnimationFrame(run);
})();
behave pretty much the same. The reason is that the next run callback is guaranteed to execute once all synchronous code (the current call to run and anything else on the call stack) completes execution, so it's not like the location causes a block in synchronous execution and the child call gets to do work as would be the case with recursion.

Why setTimeout does not work as expected?

Please See the code below.
SetTimeout should execute the seconf function after 100ms time. but first one has blocked second which is unexpected. Settimeout workd in Asynchronous way.
function funcOne(){
console.log("FuncOne invoked")
let i=0;
while(i<10000000000){i++}
console.log("Hello world")
}
function funcTwo(){
console.log("FuncTwo invoked");
}
setTimeout(funcOne,0)
setTimeout(funcTwo,100)
Output should be
FuncOne invoked
FuncTwo invoked
Hello World
But the Actual Output is
FuncOne invoked
HelloWorld
FuncTwo invoked.
Javascript cannot run in separate threads*, so all your code is running in one thread. Anything that is "asynchronous" is just various pieces of code taking turns to run. The Javascript engine will never interrupt one function because another is scheduled to run at a given moment, this is something you need to take care of yourself.
So in your case, funcOne is executed (completely), even though that takes more than 100 ms, then the timeouts are checked and since funcTwo is due to run, it then gets executed (completely).
*well, kind of maybe with workers, but it's not pretty.
The second setTimeout wont be called until your while loop finishes
So you got this order
First timeout called
FuncOne invoked
While loop finishes
Hello World
Second timeout called, after 100ms funcTwo invoked

Sequence of execution for JavaScript setTimeout

I am trying to understand the way setTimeout gets executed.
In the sample below, I was expecting to see 'Inside setTimeout' as the second line in the console log.
But, I always see 'Inside setTimeout' as the third line in the console log.
This is what I see in the log consistently:
First
Last
Inside setTimeout
Any idea why is it behaving this way?
<script>
console.log('First');
// NOTE: 0 milliseconds.
setTimeout(function() {console.log('Inside setTimeout')}, 0);
console.log('Last');
</script>
Even with a 0ms timeout, it still schedules the function to be called asynchronously. The way setTimeout works is:
Do some validations on the input
Add the function to a list to be called as of X time
Return
Later, when the specified amount of time has passed, the browser will queue a task to call the function, which will be processed by the event loop when the tasks in front of it have been processed.
It never calls the function immediately. That would chaotic; by always calling it asynchronously, it's consistent. (That's also why a promise's then and catch handlers are always called asynchronously, even if the promise is already settled.)
All of the gory details are in the specification.
Working of the setTimeout(function, delayTime) with an example:
More details can be found here.
function main(){
console.log('A');
setTimeout(
function display(){ console.log('B'); }, 0);
console.log('C');
}
main();
// Output
// A
// C
// B
The call to the main function is first pushed into the stack (as a frame). Then the browser pushes the first statement in the main function into the stack which is console.log(‘A’). This statement is executed and upon completion that frame is popped out. Alphabet A is displayed in the console.
The next statement (setTimeout() with callback exec() and 0ms wait time) is pushed into the call stack and execution starts. setTimeout function uses a Browser API to delay a callback to the provided function. The frame (with setTimeout) is then popped out once the handover to browser is complete (for the timer).
console.log(‘C’) is pushed to the stack while the timer runs in the browser for the callback to the exec() function. In this particular case, as the delay provided was 0ms, the callback will be added to the message queue as soon as the browser receives it (ideally).
After the execution of the last statement in the main function, the main() frame is popped out of the call stack, thereby making it empty. For the browser to push any message from the queue to the call stack, the call stack has to be empty first. That is why even though the delay provided in the setTimeout() was 0 seconds, the callback to exec() has to wait till the execution of all the frames in the call stack is complete.
Now the callback exec() is pushed into the call stack and executed. The alphabet C is display on the console. This is the event loop of javascript.
so the delay parameter in setTimeout(function, delayTime) does not stand for the precise time delay after which the function is executed. It stands for the minimum wait time after which at some point in time the function will be executed.
--Copied from medium
PS: The best working video example by Philip Roberts.

Will this code cause a stack overflow? Javascript setTimeout()

I have the following code, and I was wondering if this will cause a stack overflow. I am not familiar with the way the setTimeout function is handled and its consequences.
function func1() {
// some logic for the dynamicTimeout
setTimeout("func2()", dynamicTimeout);
}
function func2() {
// do something
func1();
}
setTimeout schedules a function to be executed after a delay, and the "scheduler" function's stack isn't preserved, so a stack overflow will not occur directly due to the setTimeout.
In general, many browsers enforce a minimum timeout for functions scheduled this way (so even if you pass 0 as the timeout, or don't pass one at all, the function won't be scheduled immediately). Even if this isn't the case, the function gets added to a queue of waiting operations, and will be delayed if something else if executing.
As a side note, there's no need to pass a string to setTimeout. It gets eval'd, which is sometimes insecure and generally slow. Better to just pass a function reference: setTimeout(func2, dynamicTimeout).

Categories

Resources