1.What are the values of i*3000? Is it :3000,6000,9000 OR 3000,3000,3000?
Your alerts will show 4,4,4 (the value of i
after the loop is done).
Your setTimeout()
calls will get fed a time value of 3000, 6000, 9000. setTimeout()
is non-blocking. So, the timer is set and then the for
loop continues.
The problem here is that your alert()
runs AFTER the for
loop is done. So, you will be alerting the value of i
at the end of the for
loop. If you change to use let
as in:
for (let i = 1; i <= 3; i++){
setTimeout(function(){
alert(i + " second(s) elapsed");
}, i * 3000);
}
Then, each loop value of i
will be separately accessible by your alert()
and your alert()
would show 1, 2, 3.
Also, please switch to using console.log(i + " second(s) elapsed");
as alert()
can mess with timing of things (it doesn't here, but it can).
2.setTimeout function is in the for loop.If it is called after the loop has finished and closed where is it actually stored?
It's not clear what you mean by "actually stored". setTimeout()
is a system function built into the core of the Javascript engine. Active timers are stored inside of the JS engine.
3.var i is declared in the for loop. So, when for loop is finished and closed it should be deleted from the scope. How can setTimeout functions have access to its value then?
Variables declared with var
are scoped to the containing function, not just to the loop so it is available for use anywhere in the containing function.
If you use let
instead of var
(which you should generally get in the habit of in any modern Javascript engine), then that would be scoped only to the loop itself and, in fact, there would be a separate instance of the variable for each invocation of the loop so an async callback inside the loop would have access to the i
that belongs to its specific invocation of the loop.
Notes on Garbage Collection
When using let
, the variable would be out of scope as soon as the loop was done, but it won't be eligible for garbage collection until all the code inside the loop is no longer reachable. So, as long as one of the timers is still active, code that accesses the in-scope value of i
from within the loop is still active and thus each i
cannot be garbage collected until the timer that accesses it fires.
It's important to realize that garbage collection is not controlled only be scope. A variable is eligible for garbage collection only when there is no reachable code that accesses it. Thus, the containing function or block (depending upon var
or let
where the variable was declared) may have long since completed, but if there are asynchronous operations inside the function or block that can still be called (like your timer callbacks) that still have a reference to the variable, then it still has a positive ref count and cannot yet be garbage collected.
Note, this is very different than thinking about the lifetime of a variable in a typical stack frame world like C/C++. Though the internal implementation inside the JS engine might be more involved than this, my simple model is that I think about the stack frame itself (all the variable declared with the function or block) being garbage collected itself so that it stays around until there is no code within the function (including asynchronous callbacks) that can still reach it.
Notes on non-blocking setTimeout()
It appears you may be confused about how multiple setTimeout()
calls can be called within the loop, but the loop keeps running. This is because setTimeout()
is non-blocking. That means it registers a timer internal to the JS engine and then immediately returns allowing your for
loop to continue to run. Then, some time later, after the for
loop is done and all three timers have been set, the JS engine calls the callback associated with each timer and the code inside that callback runs.
Think of the non-blocking concept like setting a reminder in your calendar. You set the reminder (say for a 4pm appointment) and then you keep going about your other business. Then, right before your 4pm appointment, the calendar notifies you of the upcoming appointment. The setting of the reminder was non-blocking. The reminder was registered and then you could keep going about your other business until then. That's the same way setTimeout()
works and pretty much all asynchronous operations in Javascript. They are non-blocking. They get initiated or scheduled or started and then they immediately return allowing your Javascript to keep doing whatever else it wanted to do. Then, sometime later, when the asynchronous operation completes and the JS interpreter is not otherwise doing something, the callback associated with the completion of the asynchronous operation gets called and the JS in that callback runs.
For more info on the event-driven nature of Javascript, see these:
How does JavaScript handle AJAX responses in the background? and the 9 referenced links in that post.
Why does a while loop block the event loop?
setTimeout waits too long in Node.js
Wait until flag=true