Call Stack while using setTimeout() - javascript

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').

Related

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.

Callback function in node.js

I am new to node.js and relatively new to javascript. I have understood how callbacks works and wanted to try out a function myself. Here is my code:
MyScript.js:
var calledfunction = function()
{
console.log("This is a called function");
for(i=0;i<1090660;i++)
{
console.log(i);
}
console.log('done');
};
var sayHello = require('./sayhello.js');
objhello = new sayHello();
objhello.setupSuite(1,calledfunction);
console.log('Next statement;');
sayhello.js
var _ = require('underscore');
module.exports = exports = CLITEST;
function CLITEST(param1,param2)
{
}
_.extend(CLITEST.prototype, {
setupSuite: function (here,callback) {
console.log(here);
console.log('This is a callback function');
callback();
}
})
The above program is run by executing > node Myscript.js
My question is : the for loop consumes 50 secs to execute and print all the numbers in the console and then only executes the line "Next statement" which is outside the callback function .
Why is this happening? because I read theories saying that the immediate statements will be executed without having to wait for the function to get executed.
The ideal output should have been : print " Next statement" and then print the contents of the for loop
but in the above case it is vice versa ?
This is not a real callback, but rather a simple function call. Function calls are obviously synchronous, as the following statements may rely on their return values.
In order to may the callback async you can use: setTimeout or setImmediate, depending on the actual use case.
See also: Are all Node.js callback functions asynchronous?
As pointed out by one of the commenters, your code is executed in a synchronous fashion. The function calls are executed one after the other, thus no magic is happening and the console.log('Next statement;'); call is executed after the execution of the callback. If you were in a situation in which you had to call a function which executed an asynchronous call (i.e., an AJAX call with a callback) then yes, you would expect the subsequent console.log to be executed right after the asynchronous call.
In other words, in your case the code represents a simple function call, while an asynchronous call would offload the computation of the callback somewhere else, thus the execution of the code where the callback function was called keeps going by printing the statement and won't wait for the execution of the callback.

How does Javascript manages recursive calls?

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 :)

SetInterval function calls

I am getting into sort of confusion here. Please go through the below code,
<script>
setInterval(function1,3000);
setInterval(function2(),3000);
function function1() {
console.log("Function1 called....");
}
function function2() {
console.log("Function2 called....");
}
</script>
As you can see I have two setInterval functions one calls function like function1 and another function2(). The output of first is perfect that gets called every 3sec and first call after 3sec. But second one gets called without the delay i.e function2.
I guess that () might be doing things there but I'm not sure about what I'm missing there. I just want to know what is happening there.
setInterval(function1,3000); instructs the JS engine to execute the function function1 every 3 seconds.
setInterval(function2(),3000); instructs the JS engine to run function2 once, then run the return value every 3 seconds. This return value is empty.
For a bit of fun try
function function2() {
console.log("Function2 called....");
return "function3();"
}
function function3() {
console.log("Function3 called....");
}
setInterval(function2(),3000);
Edit
In reponse to #harsha's comment: What do I mean by "run the return value"
setInterval(function2(),3000); will trigger the following workflow:
Initiate executing function2() (execute it, because it the brackets are given).
function2 runs to completion, then returns.
In your OQ, there is no return value from the function so it is null
The return value of my function2 is the string "function3();"
This return value is now inserted into the setInterval() call
The OQ version results in setInterval(null, 3000);, which does nothing every 3 seconds
My version results in setInterval("function3();", 3000), which calls eval("function3();"); every 3 seconds, which in turn runs function3 every 3 seconds.
In the second setInterval you are executing it right away and plugging the value returned by that function into setInterval.
For example,
setInterval(a(), 5000);
function a(){
return function(){
console.log("Executed!");
};
};
a() executed and returning the function into setInterval. You should see the console is writing Executed every 5 seconds.
This is just like math:
f(x) = x + 1
g(x) = 2
f(g(2)) = g(x) + 2 = 4
You replace g(2) with whatever it returns
(you replace a() with the function in this case)
http://jsfiddle.net/DerekL/39wNn/
The () makes the function get executed immediately in the second case. In the first case, just the pointer to function which gets executed later as the call back function.

why setTimeout is not executed in javascript

I have a function to sleep in javascript like below:
var is_sleep = true;
function sleep(time){
if (is_sleep){
is_sleep = false;
setTimeout("sleep(time)", time);
}else{
is_sleep = true;
}
}
sleep(3000);
However it runs through the statements for is_sleep=true, doesn't run through is_sleep=false statements and doesn't sleep any more.
Could someone tell what the reason is? Thank you in advance.
It's likely that setTimeout is being called, but the string passed to it is failing, as the scope will no longer contain time, which you're referencing. Try replacing that line with this:
setTimeout(function() { sleep(time); }, time);
...which defines a closure, which uses the correct scope. You could also try this:
setTimeout(sleep, time, time);
...which will pass time as an argument to sleep.
setTimeout runs asynchronously meaning it's not blocking your code execution. Perhaps you knew that, but the function will never live up to the name you chose for it.
First call sleep(3000); calls the sleep function, making the is_sleep variable false, setting a timer, and then immediately returns code execution (to whatever comes after sleep(3000); ;))
If setTimeout was called properly (setTimeout(sleep,time,time);), after 3 seconds, the function would again be called setting is_sleep back to true.

Categories

Resources