This question already has answers here:
Why is the method executed immediately when I use setTimeout?
(8 answers)
Closed 1 year ago.
const eventLoop = () => {
console.log("Start");
setTimeout(() => console.log("Settimeout"), 0)
console.log("End");
}
eventLoop();
Output:
Start
End
Settimeout
But for
const eventLoop = () => {
console.log("Start");
setTimeout(console.log("Settimeout"), 0)
console.log("End");
}
eventLoop();
Output:
Start
Settimeout
End
Please help me to understand JS execution stack and event loop in above scenario
Have you executed console.log() inside developer tools?
I think it was very confusing at first time. it has many relationship with this question.
console.log("Hello, World!");
// returns undefined
It's a kind of expression returns undefined with side effect.
const eventLoop = () => {
console.log("Start");
setTimeout(console.log("Settimeout"), 0)
console.log("End");
}
eventLoop();
console.log("Settimeout") expression in above code is executed immediately, before setTimeout function called.
Therefore, it is not related with event loop.
const eventLoop = () => {
console.log("Start");
setTimeout(() => console.log("Settimeout"), 0)
console.log("End");
}
eventLoop();
In this example you :
console.log is put on function call stack, since stack is empty it is executed.
The function passed to setTimeout is added to the tasks queue. The thing to note here is that the delay will be atleast 0ms and it is not guaranteed that the function will be called after 0ms.
Now this console.log is called using the stack.
Now, since the stack is empty and the execution has completed items from the queue are picked. So the function passed in step 2 is picked and called.
const eventLoop = () => {
console.log("Start");
setTimeout(console.log("Settimeout"), 0)
console.log("End");
}
eventLoop();
In this example, step 1 and 3 are exactly same as example#1. But, in step 2 you are not passing any function inside setTimeout you are simply calling console.log() there.
() => console.log("Settimeout") is not the same as console.log("Settimeout").
First becomes ->
() => {
return console.log("Settimeout");
}
Second is simply, console.log("Settimeout").
In short, when in second example execution reaches line 2, console.log() is executed. But in first example, a function is passed to setTimeout which has the responsibility of calling console.log().
The following URL explains very well the event loop.
https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/
This one explains what parameters receives the SetTimeOut function
https://www.w3schools.com/jsref/met_win_settimeout.asp
When you use the function in the first of your cases, the function passed as parameter is called after the next cycle in the event loop, it means you have to pass a function to be called after the cycle, but if you put "console.log" you are performing that function instantly, so there is no function to be called in the next cycle.
Related
This question already has an answer here:
Why is the behavior of setTimeout(0) and setImmediate() undefined when used in the main module?
(1 answer)
Closed 3 years ago.
setTimeout(() => {
console.log("In setTimeout");
});
setImmediate(() => {
console.log("In setImmediate");
});
Output :
As you can see, the first time I run the module, setImmediate's callback is executed first before setTimeout's callback but the second time I run the script, it is the other way around.
This is related to the event loop , you can find a good documentation about this at this link https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/ .
In short setImmediate is executed after the poll phase , setTimeout is executed during the "timers" phase so there the execution order depends on the first phase executed into your node process.
If you put setTimeout and setImmediate into an I/O callback ( pending callbacks ) the setImmediate will be executed first . ( See code below that is also present into the previous link )
// timeout_vs_immediate.js
const fs = require('fs');
fs.readFile(__filename, () => {
setTimeout(() => {
console.log('timeout');
}, 0);
setImmediate(() => {
console.log('immediate');
});
});
This question already has answers here:
How can I pass a parameter to a setTimeout() callback?
(29 answers)
Closed 3 years ago.
Example of setTimeout being executed after a synchronous code is below it
console.log('hello');
setTimeout(() => console.log('timeout'), 0);
console.log('end');
Console Output:
hello
end
timeout
Async:
function asyncForEach(array, callBack) {
array.forEach(x => setTimeout(callBack(x), 0));
}
asyncForEach([1,2,3,4], (i) => console.log(i));
console.log('end');
Console Output:
1
2
3
4
end
Synchronous:
[1,2,3,4].forEach(x => console.log(x));
console.log('end');
Console output:
1
2
3
4
end
I am trying to better understand the event loop and the task queue, and after watching a well recommended video (https://www.youtube.com/watch?v=8aGhZQkoFbQ) came across the semi statement of: "Callbacks can be synchronous and asynchronous". The speaker went on to demonstrate how the synchronous way would not end up going through the task queue, and therefore the event loop, so everything remained on the stack. However, the asynchronous way would cause the task queue to be populated with the eventual return of the setTimeout callback, which would make any synchronous below code executable since the event loop has to wait for an empty stack to insert the returned callback.
When running the above code (something I stole from him and also edited, so it could be a wrong addition on my part), the asynchronous way produces the same results as the synchronous way.
Could someone help explain why the asynchronous way does not act as the very first setTimeout example and/or provide explanation of how regular callbacks (such as the array helper methods) are not inserted into the task queue therefore never messed with by the event loop?
Your "asynchronous way" isn't asynchronous, because you called the function and passed its return value to setTimeout:
function asyncForEach(array, callBack) {
array.forEach(x => setTimeout(callBack(x), 0)); // <-- callBack(x) calls callBack immediately
}
asyncForEach([1,2,3,4], (i) => console.log(i));
console.log('end');
If you want it delayed, make a function to pass to setTimeout that it can call later:
function asyncForEach(array, callBack) {
array.forEach(x => setTimeout(() => callBack(x), 0)); // <-- Makes closure that calls callBack(x) later
}
asyncForEach([1,2,3,4], (i) => console.log(i));
console.log('end');
There's a bug in your asyncForEach function. You're calling callBack(x) immediately and then passing the result of that function (undefined) to setTimeout.
According to this stackoverflow answer,
functions passed as parameters are always callbacks, even if the intention is that the function is called synchronously...
and I've learned the event loop mechanism which basically says that call back functions are push into a waiting queue and executed after synchronous code finishes(stack empty), however in the following code
function myfun(a, b, callback) {
console.log(a);
callback();
console.log(b);
}
function cb() {console.log('hi')}
myfun(1, 2, cb) // result: 1 hi 2
the result is not 1 2 hi as I expected, from which I infer that only callback functions that fire some 'event signal' like setTimeout will be pushed into such queue but I can't find concrete reference to support it?
"Callbacks" are usually used in conjunction with asynchronous processes like ajax requests or event handlers attached to the ui. We call them "callbacks" in these cases since they need to be executed after something else and it is clear where the program's logic will pick back up this "call" after the async process is complete or triggered brings us "back" here.
Using setTimeout() you can add to the event loop stack. Using a promise you can invoke the stack on the event loop as you wait for an asynchronous process to finish.
Your code doesn't do anything to interrupt the synchronous flow of the code. This snippet shows how even though we have added a timeout of 0 which should delay the action, we can await a promise to allow the event loop's stack to run.
function myfun(a, b, callback) {
console.log(a);
callback();
console.log(b);
}
function cb() {
console.log('hi')
}
myfun(1, 2, cb) // result: 1 hi 2
// same behavior as above
function myStaticFun() {
console.log(1);
cb();
console.log(2);
}
myStaticFun();
// now same as before using a promise to wait a moment and the event loop stack is invoked during the pause
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function myEventLoopInvokingFun(a, b, callback) {
console.log(a);
setTimeout(callback, 0)
await sleep(0);
console.log(b);
}
myEventLoopInvokingFun(1, 2, cb);
It does not necessarily mean that every a callback is asynchronous and must be put into a some task queue and to be executed once synchronous code pieces (call stack is empty) finishes. The callback functions dealing with Promises are candidates for task queue. For instance in your case; cb function simply runs in a synchronous manner; so that the result is 1 hi 2 as you indicated; however if we modify your code as follows:
function myfun(a, b, callback) {
console.log(a);
window.setTimeout(callback, 0);
console.log(b);
}
function cb() {
console.log('hi');
}
myfun(1, 2, cb) // result: 1 2 hi
this will result in 1 2 hi. Even though I set the timeout to just 0 milliseconds; cb function will output after the second console.log within myfun function. I would recommend you to take a look at MDN and this good explanation of call stack, event loop, and task queues. Hope this helps.
During studying JS, the following code is mysterious to me.
The following code never print out 'this is fn'?
I am not sure fn=null; is always called first before callback function of
setTimtout(..,0)
function fn(){
console.log('this is fn');
}
var intv = setTimeout( function(){
intv = null;
if (fn) fn();
}, 0 );
fn = null;
Because this is how it will work. The callback function of setTimeout will be pushed in the queue until the stack gets empty.
The stack will get empty after the assignment fn = null;.
Now the event loop will push the callback to stack as it will be empty and hence it will execute and as the fn is not a function anymore but null so will not do any console.log.
A timeout will not run the function until:
The timeout has passed
The minimum timeout has passed
The event loop isn't busy running some other code
So you:
Define a function
Define a timeout
Set fm to null
At this stage the event loop stops being busy.
If the minimum timeout hasn't passed, then JS waits a bit.
Then the function gets called.
fn is null.
You need to understand how JavaScript execute any function. The datastrcture is called as Call Stack
Call Stack :- It’s a data structure which records the function calls, basically where in the program we are. If we call a function to
execute , we push something on to the stack, and when we return from a
function, we pop off the top of the stack.
Here in your case the complete script itself is first call we can call it main.
So first entry in stack is,
function fn(){
console.log('this is fn');
}
var intv = setTimeout( function(){
intv = null;
if (fn) fn();
}, 0 );
fn = null;
In that code the set timeout is second call after the first entry executed.
var intv = setTimeout( function(){
intv = null;
if (fn) fn();
}, 0 );
Now JavaScript call stack will execute the first entry which sets the value to fn to null at last line.
Then it will execute the timeout interval function where fn is null. Where if (fn) will return false and nothing will be executed at all.
I am a bit confused about setTimeout.I want to confirm whether the output for the following code will always be:
inside abc
inside sample
The code:
function abc() {
xyz();
// interactions and modifications in DOM
$("#id1").append("something");
$("#id2").val("set something");
$("#id3").after("create some dynamic element");
// 10 to 20 interaction more...
console.log('inside abc');
}
function xyz() {
setTimeout(function() {
sample();
},0);
}
function sample() {
console.log('inside sample')
}
It would be great,if somebody could explain the whole flow with the call stack.
Yes, it will always have that output.
The callback inside a setTimeout will not be called until the execution context is clear - i.e. the currently executing sequence of code has finished.
This means that even if you do
setTimeout(function () { console.log("1 second!"); }, 1000);
var start = +new Date();
while ((+new Date()) - start < 5000) {}
1 second! will not be logged any sooner than 5 seconds have passed.
setTimeout() will run asynchronously after finishing current execution block. So output should be same always:
inside abc
inside sample
Javascript internally manage an event queues internally for all async tasks. Every time it checks its async queue after finishing current execution block.
Yes, the console output will always be the same. setTimeout's callback function is executed asynchronously after the context that called it is cleared. When setTimeout is called, it places its callback function on the stack and returns to the current execution context. When that is done (in your example, when abc is fully executed), the callback function is executed, which in your example basically calls sample immediately. So your code output will never be different.
The fact that setTimeout's callbacks are themselves executed asynchronously can be seen if you placed a longer setTimeout function somewhere inside abc before calling xyz:
function abc() {
setTimeout(function(){
console.log('wait')
},1000);
xyz();
console.log('inside abc');
}
function xyz() {
setTimeout(function(){
sample();
} ,0);
}
function sample() {
console.log('inside sample');
}
abc();
...your console will log:
inside abc
inside sample
wait
To hold sample's execution until the longer timeout is complete you would need to place the setTimeout calling sample inside the longer setTimeout.
If setTimeout's callback is ever behaving differently, it's most likely due to being accidentally passed a function call instead of a function pointer, like this:
setTimeout(sample(),0);
instead of
setTimeout(sample,0)
Also, just in case you didn't know (or for others), you can add
debugger;
at any point(s) in your Javascript code and then run the code to view the callstack at that point using dev tools (in Chrome it is in the right panel under 'Sources').