skip to Main Content

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


  1. You can imagine that setTimeout() and setInterval() are implemented something like this:

    class Timer {
      static allTimers = {};
      static timerId = 0;
    
      constructor(timeout, func, interval) {
        this.timerId = ++timerId;
        this.timeout = timeout;
        this.func = func;
        this.interval = interval;
        this.expire_time = Date.now() + timeout;
        this.allTimers[timerId] = this;
        addTimerToEventLoop(this);
      }
      
      clear(id) {
        let timer = this.allTimers[id];
        if (timer) {
          removeTimerFromEventLoop(timer);
        }
    }
    
    function setTimeout(timeout, func) {
      let newTimer = new Timer(timeout, func, false);
      return newTimer.timerId;
    }
    
    function setInterval(timeout, func) {
      let newTimer = new Timer(timeout, func, true);
      return newTimer.timerId;
    }

    The functions addTimerToEventLoop() and removeTimerFromEventLoop() 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 each Timer object. If the Timer class were actually visible to user code, instead of being internal to the JavaScript engine, you would be able to find them on Timer.allTimers.

    Login or Signup to reply.
  2. The HTML Standard defines the initialisation steps for setTimeout. It includes the definition of a task in step 5:

    1. Let task be a task that runs the following substeps:

          [1. … 2. …]

      1. If handler is a Function, then invoke handler

    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:

    1. Let completionStep be an algorithm step which queues a global task on the timer task source given global to run task.

    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 calling setTimeout and the eventual execution of the callback.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search