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

问题描述 投票:4回答:2
timer =  window.setTimeout(function () {
    //do something
    window.setTimeout(arguments.callee, 1000);
}, 1000);

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

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

超出最大调用堆栈大小

在调试它时,找到变量范围不包括先前执行的“setTimeout函数”的范围

谁能解释一下?

最好是文档。

javascript browser settimeout
2个回答
7
投票

setTimeout是异步的(它在执行回调之前返回),并且回调将在新的空堆栈帧上执行。这就是整个目的。

它不是递归调用,需要保留范围(在非tail-call优化函数的情况下)。但这也意味着该功能变得阻塞,这不是你想要的。


0
投票

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

更新:您可以检查规格here,但我正在复制文本:

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

  1. 令handle是一个大于零的用户代理定义的整数,它将标识此调用要设置的超时。
  2. 将句柄添加到句柄的活动超时列表中。
  3. 在活动超时列表中获取定时任务句柄,并将任务作为结果。
  4. 获取超时,并将超时作为结果。
  5. 如果当前正在运行的任务是由setTimeout()方法创建的任务,并且timeout小于4,则将timeout增加到4。
  6. 返回句柄,然后异步继续运行此算法。
  7. 如果方法上下文是Window对象,请等待与方法上下文关联的Document完全处于活动状态超过毫秒(不一定是连续)。
  8. 否则,如果方法上下文是WorkerUtils对象,请等待,直到超时毫秒已经过去,而工作程序未挂起(不一定是连续)。
  9. 否则,按照规范中的描述进行操作,该规范定义WindowTimers接口由其他对象实现。
  10. 等到此算法的任何调用在此超时等于或小于此已完成的超时之前启动。 (可选)等待另一个用户代理定义的时间长度。
© www.soinside.com 2019 - 2024. All rights reserved.