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');
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 wanted to have a better understanding of how the event loop and asynchronous code works in Javascript. There is a ton of resources online but I could not find an answer to my question
Everyday I mostly use callbacks, promises, async/awaits, but at the end I am simply relying on already asynchronous methods.
Therefore I wanted to know how it works, creating an async function from scratch, and deal with blocking code (or should I say slow code, that is not an HttpRequest or anything that is already provided to us).
For example taking while loop with a very high condition to stop it, should take a second to finish. And this is what I decided to implement for my tests.
After my research, I could read that one way of making my code asynchronous, would be to use setTimeout with a 0ms delay (placing a message in the event queue, that will be executed after the next tick)
function longOperation(cb) {
setTimeout(function() {
var i = 0;
while (i != 1000000000) { i++; }
cb();
}, 0);
}
longOperation(() => {
console.log('callback finished');
})
console.log('start');
My question is:
When my code is finally going to be executed, why isn't it blocking anymore ? What is the difference between executing it normally, and placing a message that the event loop will pick to push it to the call stack ?
The following video shows how the event loop handles a setTimeout with 0 delay.
JavaScript Event loop with setTimeout 0
However, the code executed is a simple console log. In my example, this is a "long" operation...
The outer code executes to completion.
The setTimeout 0 timer expires immediately, so its callback runs right away and executes to completion (the long-running while loop and its callback).
During both of these code execution phases, no other JavaScript user code will run.
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.
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.
The following code is taken from Project Silk (a Microsoft sample application)
The publish method below loops thru an an array of event callBacks and executes each one. Instead of using a for loop setInterval is used instead.
The documentation says this allows each subscriber callback to be invoked before the previous callback finishes. Is this correct? I thought the browser would not allow the execution of the function inside the interval to run until all prior executions of it had finished.
Is this really any different than doing a for loop?
that.publish = function (eventName, data)
{
var context, intervalId, idx = 0;
if (queue[eventName])
{
intervalId = setInterval(function ()
{
if (queue[eventName][idx])
{
context = queue[eventName][idx].context || this;
queue[eventName][idx].callback.call(context, data);
idx += 1;
}
else { clearInterval(intervalId); }
}, 0);
}
Using setInterval here does make the execution sort of "asynchronous", because it schedules the execution of the callback for the next time the main execution thread is available.
This means that the callback executions should not block the browser because any other synchronous processing will take place before the callbacks (because the callbacks are scheduled to run only when the main execution thread has a spare millisecond) - and that's what makes this construct "better" than a regular for loop - the fact that the callbacks won't block the browser and cause the dreaded "This page has a script that's taking too long" error.
The side effect of this scheduling pattern is that the timeout is only a "suggestion" - which is why they use 0 here.
See: http://ejohn.org/blog/how-javascript-timers-work/
setInterval(..., 0) can be used to yield control to the browser UI, to prevent it from freezing if your code takes a long time to run.
In this case, that.publish will exit almost immediately before any callback has been executed. Each callback will then run "in the background" - they will be placed in the event loop, and each one will yield to the browser to do it's thing before the next callback is executed.
This seems like a good idea in event processing, because you don't want event processing to freeze the browser even if there are a lot of them or some take a long time to finish.
About the documentation - as stated, it is incorrect. Javascript is single-threaded. But if you were to call publish() a few times in a row, it is true that those calls would all finish before any callbacks are executed, because of the setTimeout. Maybe this is what the documentation means?