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.
Related
setTimeout(function(){
console.log("m");
}, 0);
console.log("s");
Why does this code print "s" before "m", even if the setTimeout callback is supposed to wait for 0 ms?
A browser or node.js always run a single threaded event loop to run your code. On the first run it will always run your synchronous code but may also que up asynchronous events that will call back later. Thats why we call the function here callback function it will be called later.
setTimeout is a microtask.
That means the function that you see isnt gona executed immedantly, it is gonna first queued up and will be executed within the next event loop.
Also a sidefact: 0 ms just means it will minimum wait 0 ms not exact 0
When you create a promise, or call an async function, or set a timeout for 0 milliseconds, the function is immediately queued into the Javascript event loop. Essentially, the function is added to a queue of functions to call, and once the javascript interpreter has nothing to do it'll start calling those functions. So, when you set a timeout for 0 milliseconds, it queues the console.log("m"), then calls the console.log("s"), then it has nothing to do so it finishes the queued console.log("m"), which is why it's out of order.
it just because JS is single-threaded and event loop works that way.
setTimeout has written in a way that it will send you function or whatever you want to do in a callback queue.
and then move forward to the next line, once next line executed it will not run your setTimeout part, or in other words, it will not process the setTimeout part until the stack is not empty.
so this is your code, and it will execute like this.
setTimeout(function () {
console.log("m");
} , 0)
console.log('s');
the first line will execute and it will send the inner part of setTimeout to callback queue and move to the 2nd line.
while 2nd line is executing the setTimeout part will wait till the stack is not emplty and as soon as 2nd line finishes execution,
the setTimeout part will execute,
maybe it's confusing by words, let's see this in action. I bet you can not get a better example than this to understand it, it's explained in the best way by Philip robert.
because JS code goes in order one by one. When you specifying setTimeout to 0 is still waiting, in C++ lang this would be something like this 0.000000245ms, and JS runs often on C++/C browser.
try this simple example
for (let x = 0; x < 500; x++) {
setTimeout(() => console.log(x), 0);
}
console.log('hello');
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');
I have the following code:
function sayHiLater(){
var greeting = "Hi!";
setTimeout(function() {
console.log(greeting);
}, 3000);
console.log("Hello before hi");
}
sayHiLater();
I would like to better understand how event listeners work under the hood,
so in my example above, as setTimeOut is being executed, what really happens?
I know it creates a new execution context, but my question is; does that execution context is simply being delayed for 3 seconds, meaning the execution stack is moving on to other things in the meanwhile, and as the 3 seconds are over it comes back to that execution context, or is it simply passing to the browser engine some sort of a reference of the anonymous function argument, telling it when to fire, and then right away the setTimeOut execution context is being popped off the execution stack. Or am I just completely far off from what's really happening. Thank you for your time.
Is it simply passing to the browser engine some sort of a reference of the anonymous function argument, telling it when to fire, and then right away the setTimeOut execution context is being popped off the execution stack.
Yes, that's exactly what is happening. The setTimeout execution context immediately returns (and jumps to the next statement, your console.log).
Then after your current turn completes and no more code is to execute, the engine goes back to the event loop and waits for something to happen. After 3 seconds, the time is ready to fire the callback, and when no other code is already executing the event loop starts the anonymous function.
So setTimeout does not really call its callback, it only schedules it for later. It will be called by the event loop itself when the timer has run out.
Notice that the anonymous function that is put on the timer is a closure (it closes over the greeting variable), so the variable environment ("scope") of sayHiLater will be retained (not garbage-collected) even after the sayHiLater execution context is popped off the stack, until the callback is going to be executed.
If the callback for a setTimeout invocation is added to the job queue (for example, if it is next on the job queue), and a clearTimeout is called on the current tick of the event loop, supplying the id of the original setTimeout invocation. Will the setTimeout callback on the job queue be run?
Or does the runtime magically remove the callback from the job queue?
No, it won't run; it will be queued and then subsequently aborted. The specificiation goes through a number of steps when you call setTimeout, one of which (after the minimum timeout, plus and user-agent padded timeouts etc) is eventually:
Queue the task task.
This appears to happen regardless of whether or not the handle that was returned in step 10 has been cleared - ie a call to setTimeout will always result in something being enqueued.
When you call clearTimeout, it:
must clear the entry identified as handle from the list of active timers
ie it doesn't directly affect the process already kicked off in the call to setTimeout. Note however that further up that process, task has been defined as:
Let task be a task that runs the following substeps:
If the entry for handle in the list of active timers has been cleared, then abort this task's substeps.
So when the task begins executing, it will first check if the handle has been cleared.
No, it won't be ran.
I don't know which source should be used to back it up officially, but it's at least easy to try for yourself.
function f() {
var t1 = setTimeout(function() { console.log("YES"); }, 2000);
sleep(3000);
clearTimeout(t1);
console.log("NO");
}
I was goofing around with JavaScript, and a notice a strange behavior (strange for me at least. . .)
So I did a SSCCE here it goes:
I have a div named "myDiv"
function changeText(text){
document.getElementById("myDiv").innerHTML=text;
}
function recursiveCall(counter){
if(counter){
setTimeout(function(){
recursiveCall(--counter);
changeText(counter);
},750);
}
}
recursiveCall(10);
Live example: http://jsfiddle.net/T645X/
So I'm changing the text on the div, and what happens is that the text goes from 9 to 0, while I thought that it was suppose to go from 0 to 9, since the recursive changeText(counter); call is before calling the method that actually changes the text.
The function contains a timeout which is asynchronous.
setTimeout(function(){
recursiveCall(--counter);// calls the next function, which will call the next
// and print in a timeout
changeText(counter); // print
},750);
The text is changed before the recursive call hits the timeout.
If you'd like to, you can move the print call from outside the timeout, which would result in the expected behavior as such:
function recursiveCall(counter){
if(counter){
recursiveCall(--counter);
setTimeout(function(){
changeText(counter);
},750);
}
}
(Although, note that here the printing is not timed apart, and we're relying somewhat on undefined behavior assuming it'd print first just because we put the timer first)
If you would like it to still print in delays, you can tell the function it's done. Recursion will still be done initially, but each level will tell the level above it that it is done:
function recursiveCall(counter,done){
if(counter){
// note how recursion is done before the timeouts
recursiveCall(counter-1,function(){ //note the function
setTimeout(function(){ //When I'm done, change the text and let the
changeText(counter-1); //next one know it's its turn.
done(); // notify the next in line.
},750);
});
}else{
done(); //If I'm the end condition, start working.
}
}
Here is a fiddle implementing this.
Strictly speaking there is no recursion here.
The call to setTimeout just adds a callback to a list of scheduled timer events.
Much of the time, your browser is just sat there waiting for events, it processes those (i.e. runs your event handlers) and then goes back to waiting for events.
So in this case what you're doing is:
recursiveCall(10)
timer event and callback added to the queue
function exits
... waits 750 ms ...
timer event fires, callback pulled from the queue and invoked
-> recursiveCall(9) invoked
-> timer event and callback added to the queue
-> changeText(9) invoked
callback function exits
... waits 750 ms ...
timer event fires, callback pulled from the queue and invoked
-> recursiveCall(8) invoked
-> timer event and callback added to the queue
-> changeText(8) invoked
callback function exits
and so on...
I call this pseudo-recursion, because although it looks somewhat like classical recursion, each invocation starts at the same "stack frame", i.e. if you asked for a stack trace there would typically only be one (or in your case sometimes two) instance of recursiveCall present at a time.
One thing to understand is that it's not recursion in the first place; if your function didn't have a proper exit clause, this could go on forever without running into a blown stack.
The reason is that any function you pass to setTimeout() is run outside of the current execution context; in other words, the code "breaks out" of your function.
If you want a recursive call with 750ms in between them, you could do something like this:
function recursiveCall(counter, fn)
{
if (counter) {
recursiveCall(--counter, function() {
changeText(counter);
setTimeout(fn, 750);
});
} else if (fn) {
fn(); // start chain backwards
}
}
It creates a chain of callbacks when it recurses and the exit clause sets the whole chain motion, backwards :)