I have a simple program that looks like this:
console.log("Start of the program execution!");
setTimeout(() => {
console.log("I ran after a second!");
}, 1000);
console.log("The end of the file!");
Then, the question I have is: Where does the anonymous function live while the timer is running and the function is not put onto the call stack?
If I had a normal function definition, the code would look like this:
function doSth()
{
console.log("I ran after a second!");
}
console.log("Start of the program execution!");
setTimeout(doSth, 1000);
console.log("The end of the file!");
then, the function doSth()
would still live in the global memory after the call stack became empty and thus the setTimeout()
could use its reference to call it after the set time. This arrangement makes perfect sense to me. The problems arise when I use an anonymous function and make some observations.
For some observations, I first put the debugger on line 5 of the program; the console.log("The end of the file!");
. Then I take a look at the Scope
of the Developer Tools. The anonymous function is nowhere to be seen.
For the next observation, I put the debugger on the console.log()
inside the setTimeout()
function, which is line 3 of the program. Then indeed the call stack has the anonymous function on it when we are running it.
Thus, these two observations bring forward the confusion for me. If the anonymous function was not present in the global memory AFTER the setTimeout()
was called, then how can it be pushed to the call stack when the setTimeout()
finishes its job? Does the function "go with" the setTimeout()
to the webAPIs
domain and then come back from there?
2
Answers
You can imagine that
setTimeout()
andsetInterval()
are implemented something like this:The functions
addTimerToEventLoop()
andremoveTimerFromEventLoop()
are the internval interface with the event loop that makes it run them on the timed schedule.The functions are held in the
func
property of eachTimer
object. If theTimer
class were actually visible to user code, instead of being internal to the JavaScript engine, you would be able to find them onTimer.allTimers
.The HTML Standard defines the initialisation steps for
setTimeout
. It includes the definition of a task in step 5:In other words, the task created by
setTimeout
holds a reference to the callback (handler) inside a task object — no matter whether it is anonymous or named. By general principle in JavaScript, whenever an object has at least one reference, it will not be candidate for garbage collection.When the timeout period has expired, a step is executed — called the completionStep –, described in step 11 in the same procedure:
The actual execution of that algorithm step is described in run steps after timeout.
But the essential thing is that the agent (host, webbrowser) that provides
setTimeout
has a reference to the callback function during the time of callingsetTimeout
and the eventual execution of the callback.