为什么 setTimeout 调用的函数没有调用栈限制?

IT技术 javascript browser settimeout
2021-02-03 16:19:24
timer =  window.setTimeout(function () {
    //do something
    window.setTimeout(arguments.callee, 1000);
}, 1000);

结果是这些代码运行良好。

但为什么它不会导致下面的错误?

超出最大调用堆栈大小

调试的时候发现变量作用域不包括之前执行的“setTimeout函数”的作用域

谁能解释一下?

最好有文档。

2个回答

setTimeout是异步的(它在执行回调之前返回),并且回调将在一个新的空堆栈帧上执行。这就是全部目的。它永远不会溢出堆栈。

它不是递归调用,需要保留其作用域(在非尾调用优化函数的情况下)。但这也意味着函数变得阻塞,这不是你想要的。

有文件可以解释你所说的吗?
2021-03-13 16:19:24
@SKing7 有一个 DOM 计时器 API,它指定了它应该如何工作,我可以向您发送一个指向 chrome 实现的链接 - 但这并没有太大帮助。whatwg.org/specs/web-apps/current-work/multipage/timers.html这里是计时器 API。
2021-03-22 16:19:24
@SKing7:我刚刚找到developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/EventLoop如果您正在寻找官方的东西,HTML5 计时器规范也可以解释这一点,但仅限于非常复杂的术语。
2021-03-31 16:19:24
哦,他在问为什么它不会导致 StackOverflow。我完全错过了。您可能想提一下,您可以在具有异步堆栈跟踪的较新版本的 chrome 中获取堆栈跟踪。
2021-04-06 16:19:24

这是因为 Timeout 回调没有像您假设的那样存储在堆栈中:有一个队列,等待在自己的堆栈中执行。并且在您的代码中,队列在前一次执行完成时被填满,因此队列没有增长。

更新:您可以在此处查看规格,但我正在复制文本:

setTimeout() 方法必须运行以下步骤:

  1. 令句柄是一个用户代理定义的大于零的整数,用于标识此调用设置的超时时间。

  2. 将条目添加到句柄的活动超时列表中。

  3. 获取活动超时列表中的定时任务句柄,并让任务成为结果。

  4. 获取超时,并让超时成为结果。

  5. 如果当前运行的任务是 setTimeout() 方法创建的任务,并且 timeout 小于 4,则将 timeout 增加到 4。

  6. 返回句柄,然后继续异步运行该算法。

  7. 如果方法上下文是 Window 对象,则等待与方法上下文关联的 Document 完全激活再超时毫秒(不一定是连续的)。

  8. 否则,如果方法上下文是 WorkerUtils 对象,请等待超时毫秒已过且工作器未挂起(不一定连续)。

  9. 否则,按照定义 WindowTimers 接口由其他对象实现的规范中的描述进行操作。

  10. 等到此算法的任何调用在超时等于或小于此算法的调用完成之前开始。

    或者,等待用户代理定义的进一步时间长度。

有文件可以解释你所说的吗?
2021-03-30 16:19:24