setTimeout 的匿名回调函数存储在哪里?

问题描述 投票:0回答:1

我有一个简单的程序,如下所示:

console.log("Start of the program execution!");

setTimeout(() => {
    console.log("I ran after a second!");
}, 1000);

console.log("The end of the file!");

然后,我的问题是:当计时器运行并且函数没有放入调用堆栈时,匿名函数位于哪里?

如果我有一个普通的函数定义,代码将如下所示:

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!");

然后,在调用堆栈变空后,函数

doSth()
仍会存在于全局内存中,因此
setTimeout()
可以在设定时间后使用其引用来调用它。这种安排对我来说非常有意义。当我使用匿名函数并进行一些观察时,问题就出现了。

为了进行一些观察,我首先将调试器放在程序的第 5 行;

console.log("The end of the file!");
。然后我看一下开发者工具的
Scope
。匿名函数无处可见。

为了进行下一步观察,我将调试器放在

console.log()
函数内的
setTimeout()
上,即程序的第 3 行。那么当我们运行它时,调用堆栈上确实有匿名函数。

因此,这两个观察给我带来了困惑。如果在调用

setTimeout()
后匿名函数不存在于全局内存中,那么当
setTimeout()
完成其工作时如何将其推送到调用堆栈?该函数是否“跟随”
setTimeout()
webAPIs
域,然后从那里返回?

javascript settimeout anonymous-function asynccallback
1个回答
0
投票

你可以想象

setTimeout()
setInterval()
是这样实现的:

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;
}

函数

addTimerToEventLoop()
removeTimerFromEventLoop()
是事件循环的内部接口,使其按定时计划运行它们。

这些函数保存在每个

func
对象的
Timer
属性中。如果
Timer
类实际上对用户代码可见,而不是在 JavaScript 引擎内部,那么您将能够在
Timer.allTimers
上找到它们。

© www.soinside.com 2019 - 2024. All rights reserved.