JavaScript是否用完了超时ID?

时间:2018-11-01 13:42:19

标签: javascript settimeout setinterval

令人惊讶的是,我在网络上的任何地方都找不到该问题的答案。

在文档it is stated中,setTimeout和setInterval共享相同的ID池,并且ID 从不重复。如果是这种情况,那么它们最终必须耗尽,因为there is a maximum number计算机可以处理吗?那会发生什么,您不能再使用超时了?

1 个答案:

答案 0 :(得分:3)

TL; DR;

这取决于浏览器的引擎。

在Blink和Webkit中:

  • 并发计时器的最大数量为2 31 -1。
  • 如果您尝试使用更多功能,则浏览器可能会由于无休止的循环而冻结。

官方规格

来自W3C docs

  

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

     
      
  1. handle 是用户代理定义的一个大于零的整数,它将标识此调用要设置的超时。

  2.   
  3. handle 的活动超时列表中添加一个条目。

  4.   
  5. [...]

  6.   

也:

  

每个实现WindowTimers接口的对象都有一个活动超时列表和一个活动间隔列表。这些列表中的每个条目均由一个数字标识,该数字在实现WindowTimers接口的对象的生命周期内,在其列表中必须唯一。

注意:尽管 W3C 提到了两个列表,但WHATWG spec确立了setTimeoutsetInterval共享一个共同的活动计时器列表。这意味着您可以使用clearInterval()删除由setTimeout()创建的计时器,反之亦然。

基本上,每个用户代理都可以按自己的意愿自由实现 handle ID ,唯一的要求是每个对象唯一的整数;您可以获得与浏览器实现一样多的答案。

例如,让我们看看Blink在做什么。

眨眼实现

上一个注释:找到眨眼的实际源代码是not such an easy task。它属于Chromium codebase中镜像的GitHub。我将链接GitHub(其当前最新标签:72.0.3598.1),因为它是导航代码的更好工具。三年前,他们将提交内容推送到 chromium / blink / 。如今, chromium / third_party / WebKit 上正在进行积极的开发,但是正在进行discussion的新迁移。

在Blink(以及显然具有非常相似的代码库的WebKit中)中,维护上述活动计时器列表的责任是属于每个DOMTimerCoordinatorExecutionContext

// Maintains a set of DOMTimers for a given page or
// worker. DOMTimerCoordinator assigns IDs to timers; these IDs are
// the ones returned to web authors from setTimeout or setInterval. It
// also tracks recursive creation or iterative scheduling of timers,
// which is used as a signal for throttling repetitive timers.
class DOMTimerCoordinator {

DOMTimerCoordinator将计时器存储在blink::HeapHashMap集合timers_DOMTimerCoordinator::InstallNewTimeout()集合中,该密钥是(符合规格)TimeoutMap类型:

int

回答您的第一个问题(在Blink的地方):每个上下文的活动计时器的最大数量为2 31 -1 ;比您提到的JavaScript using TimeoutMap = HeapHashMap<int, Member<DOMTimer>>; TimeoutMap timers_; (2 53 -1)要低得多,但对于正常使用情况而言仍然足够。

对于第二个问题,“ 接下来会发生什么,您不能再使用超时了?”,到目前为止,我只有部分答案。

新计时器由NextID()创建。它调用私有成员函数DOMTimer::Create来检索可用的整数键,并调用circular_sequential_id_来实际创建计时器对象。然后,它将新计时器和相应的键插入MAX_SAFE_INTEGER中。

timers_

int timeout_id = NextID(); timers_.insert(timeout_id, DOMTimer::Create(context, action, timeout, single_shot, timeout_id)); 以1到2的循环顺序获取下一个id 31 -1:

NextID()

它将seems that nothing的值加1,或者如果超出上限则将其设置为1(尽管int DOMTimerCoordinator::NextID() { while (true) { ++circular_sequential_id_; if (circular_sequential_id_ <= 0) circular_sequential_id_ = 1; if (!timers_.Contains(circular_sequential_id_)) return circular_sequential_id_; } } + 1调用UB,但是大多数C实现返回INT_MAX)。

因此,当INT_MIN用完ID时,请从1开始重试,直到找到一个空闲的。

但是,如果全部使用它们会发生什么?是什么阻止DOMTimerCoordinator进入无限循环? contacted Blink developers。 Blink开发人员很可能在假设永远不会同时存在2 31 -1个计时器的情况下对NextID()进行编码。这说得通;对于NextID()返回的每个字节,如果DOMTimer::Create()已满,则需要GB的RAM来存储。如果存储长时间的回调,则总计可能达到TB。更不用说创建它们所需要的时间了。

无论如何,令人惊讶的是,没有实现无尽循环的防护措施,所以我有{{3}},但到目前为止我没有任何回应。如果他们回复,我将更新我的答案。