JavaScript 是否用完了超时 ID? [英] Does JavaScript run out of timeout IDs?

查看:40
本文介绍了JavaScript 是否用完了超时 ID?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Surprisingly I can not find the answer to this question anywhere on the web.

在文档中说明setTimeout 和 setInterval 共享相同的 id 池,并且 id 将永远重复.如果是这种情况,那么它们最终必须用完,因为 有一个最大数量计算机可以处理?那么会发生什么,你不能再使用超时了吗?

In the documentation it is stated that setTimeout and setInterval share the same pool of ids, as well as that an id will never repeat. If that is the case then they must eventually run out because there is a maximum number the computer can handle? What happens then, you can't use timeouts anymore?

推荐答案

TL;DR;

这取决于浏览器的引擎.

It depends on the browser's engine.

在 Blink 和 Webkit 中:

In Blink and Webkit:

  • 最大并发计时器数为 231-1.
  • 如果您尝试使用更多,您的浏览器可能会因无限循环而死机.

来自 W3C文档:

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

The setTimeout() method must run the following steps:

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

  1. Let handle be a user-agent-defined integer that is greater than zero that will identify the timeout to be set by this call.

句柄的活动超时列表添加一个条目.

Add an entry to the list of active timeouts for handle.

[...]

还有:

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

Each object that implements the WindowTimers interface has a list of active timeouts and a list of active intervals. Each entry in these lists is identified by a number, which must be unique within its list for the lifetime of the object that implements the WindowTimers interface.

注意:虽然 W3C 提到了两个列表,WHATWG 规范 确定 setTimeoutsetInterval 共享一个公共的活动计时器列表.这意味着您可以使用 clearInterval() 删除由 setTimeout() 创建的计时器,反之亦然.

Note: while the W3C mentions two lists, the WHATWG spec establishes that setTimeout and setInterval share a common list of active timers. That means that you can use clearInterval() to remove a timer created by setTimeout() and vice versa.

基本上,每个用户代理都可以随心所欲地实现句柄 ID,唯一的要求是每个对象都是唯一的整数;您可以获得与浏览器实现一样多的答案.

Basically, each user agent has freedom to implement the handle Id as they please, with the only requirement to be an integer unique for each object; you can get as many answers as browser implementations.

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

Let's see, for example, what Blink is doing.

上一条说明:找到真正的源代码并不是一件容易的事眨.它属于 Chromium 代码库,在 GitHub.我将链接 GitHub(其当前最新标签:72.0.3598.1),因为它有更好的代码导航工具.三年前,他们正在推动对 chromium/blink/ 的提交.如今,chromium/third_party/WebKit 正在积极开发,但有一个 讨论 关于新的迁移.

Previous note: It's not such an easy task to find the actual source code of Blink. It belongs to the Chromium codebase which is mirrored in GitHub. I will link GitHub (its current latest tag: 72.0.3598.1) because its better tools to navigate the code. Three years ago, they were pushing commits to chromium/blink/. Nowadays, active development is on chromium/third_party/WebKit but there is a discussion going on about a new migration.

在 Blink(和 WebKit,显然有一个非常相似的代码库)中,负责维护上述活动计时器列表的是 DOMTimerCoordinator 属于每个ExecutionContext.

In Blink (and in WebKit, which obviously has a very similar codebase), the responsible of maintaining the aforementioned list of active timers is the DOMTimerCoordinator belonging to each ExecutionContext.

// 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(别名TimeoutMap)集合timers_哪个键是(符合规范)int 类型:

The DOMTimerCoordinator stores the timers in the blink::HeapHashMap (alias TimeoutMap) collection timers_ which key is (meeting the specs) int type:

using TimeoutMap = HeapHashMap<int, Member<DOMTimer>>;
TimeoutMap timers_;

回答你的第一个问题(在 Blink 的上下文中):每个上下文的最大活动计时器数是 231-1;远低于您提到的 JavaScript MAX_SAFE_INTEGER (253-1),但对于正常用例来说仍然绰绰有余.

That answer your first question (in the contex of Blink): the maximum number of active timers for each context is 231-1; much lower than the JavaScript MAX_SAFE_INTEGER (253-1) that you mentioned but still more than enough for normal use cases.

对于您的第二个问题,然后会发生什么,您不能再使用超时?",到目前为止我只有部分答案.

For your second question, "What happens then, you can't use timeouts anymore?", I have so far just a partial answer.

新计时器由 DOMTimerCoordinator::InstallNewTimeout().它调用私有成员函数 NextID() 检索可用的整数键和 DOMTimer::Create 用于实际创建计时器对象.然后,它将新的计时器和相应的密钥插入到 timers_ 中.

int timeout_id = NextID();
timers_.insert(timeout_id, DOMTimer::Create(context, action, timeout,
                                            single_shot, timeout_id));

NextID() 从 1 到 2 的循环序列中获取下一个 id31-1:

NextID() gets the next id in a circular sequence from 1 to 231-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_;
  }
}

它将 circular_sequential_id_ 或者如果超出上限则将其设置为 1(尽管 INT_MAX+1 调用 UB,但大多数 C 实现返回 <代码>INT_MIN).

It increments in 1 the value of circular_sequential_id_ or set it to 1 if it goes beyond the upper limit (although INT_MAX+1 invokes UB, most C implementations return INT_MIN).

因此,当 DOMTimerCoordinator 用完 ID 时,从 1 开始重试,直到找到空闲的 ID.

So, when the DOMTimerCoordinator runs out of IDs, tries again from 1 up until it finds one free.

但是,如果它们都在使用中会怎样?什么阻止 NextID() 进入无限循环?似乎没什么.很可能,Blink 开发人员在假设永远不会有 231-1 个计时器并发的情况下编码 NextID().这说得通;对于 DOMTimer::Create() 返回的每个字节,如果 timers_ 已满,您将需要 GB 的 RAM 来存储它.如果您存储长回调,它可以增加到 TB.更不用说创建它们所需的时间了.

But, what happen if they are all in use? What does prevent NextID() from entering in a endless loop? It seems that nothing. Likely, Blink developers coded NextID() under the assumption that there will never be 231-1 timers concurrently. It makes sense; for every byte returned by DOMTimer::Create() you will need a GB of RAM to store timers_ if it is full. It can add up to TB if you store long callbacks. Let alone the time needed to create them.

无论如何,没有实现对无限循环的防护,这看起来令人惊讶,所以我有 联系了 Blink 开发人员,但到目前为止我没有任何回应.如果他们回复,我会更新我的答案.

Anyway, it looks surprising that no guard against an endless loop has been implemented, so I have contacted Blink developers, but so far I have no response. I will update my answer if they reply.

这篇关于JavaScript 是否用完了超时 ID?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆