哪个队列与 requestAnimationFrame 关联?

b3r*_*rry 1 javascript event-loop requestanimationframe

今天我在接受采访时被问到这个问题。我无法回答这个问题,面试官说有一个特殊的队列用于 requestAnimationFrame 回调。但我找不到任何这方面的信息。

如果 rAF 有它自己的队列,那么为什么这个队列从未在任何地方被提及?当我们谈论事件循环时,我们只提到宏任务队列和微任务队列?

Kai*_*ido 6

当我们谈论事件循环时,我们只提到宏任务队列和微任务队列?

首先,规范中没有提到“宏”任务,只有任务微任务(然后是回调,稍后会详细介绍)。

然后,几乎每个任务源在现代浏览器中都有自己的任务队列,尽管目前还不需要。因此,不仅有两个队列,一个是微任务队列,另一个是所有任务队列,还有很多任务队列(每个MessagePort实例可以有自己的任务队列)。这允许每个任务源具有不同的优先级。例如,用户界面事件可以在网络事件之前得到处理。

requestAnimationFrame回调甚至没有在任务队列中排队。此方法安排一个回调(在规范1中)不是从任务调用,而是从事件循环中称为“更新渲染”的特殊位置调用,它本身仅偶尔访问一次(通常当监视器发送VSync 信号且文档处于活动状态),这还将触发滚动调整大小事件、Web 动画更新、ResizeObserver回调等以及页面的渲染。

从概念上讲,所有这些步骤都不会在任务中执行,这一点很重要,因为这意味着从这些回调排队的任何任务都不会在下一次渲染之前执行,同时仍然确保ResizeObserver调整大小事件调度的回调将被执行。之前打电话过。

动画帧回调存储在一个有序映射中,称为动画帧回调映射。它本身不是一个队列cancelAnimationFrame(),因为我们可以通过该方法“取消”回调。此外,这允许在运行动画帧回调算法开始时获取所有键,该算法本身允许安排从此类回调到下一个动画帧的新回调,而不会永远阻塞事件循环(如果它是一个队列,该算法将不断地调用新的回调,就像在微任务检查点中一样)。

但这么多细节有点迂腐,除非你真的喜欢这种东西,否则你不需要知道更多

  • 大多数本机事件和 Web API 回调都在任务队列中排队,这些任务队列在事件循环开始时通过优先级系统进行访问,
  • 每次调用回调后都会执行所有微任务,如果从微任务中排队微任务,您可能会陷入事件循环,
  • 一些与渲染相关的本机事件和动画帧在事件循环中自己的位置进行处理。

不过,我认为最好理解事件循环中存在这种特殊的更新渲染步骤,它与其他排队任务不同,因为它不参与任务优先级系统。我经常读到它具有更高的优先级,但在我看来,这种说法是错误的,并且考虑到我们很快就会真正控制某些任务的优先级,它将变得更加重要。它还有助于理解何时执行样式重新计算以及与(同步)DOM 更新的关系,以及与浏览器中渲染相关的其他内容。但是,如果您不申请涉及浏览器渲染细节的职位,也许他们只是期望(IMO 相当糟糕)口语“在渲染队列中”,就像P.Roberts 的 Loupe中所使用的那样。

1:Firefox 实际上甚至对这些任务也进行了排队,但它们以一种不可观察的方式进行操作。

  • 1. 关于事件循环的规范性讨论是 [Jake Archibald 的讨论](https://www.youtube.com/watch?v=cCOL7MC4Pl0),它确实清楚地表明事件循环中有一个渲染步骤,这与通常的任务是分开的。2. 正如第一点所暗示的,也许是因为你的消息来源不是最好的。请注意,理论上仍然可以有一个队列,但很快情况就不会如此。至于任务优先级,它可能有点稀疏,但我想您可以在此[规格孵化](https://github.com/WICG/scheduling-apis)中找到一些材料。 (2认同)
  • 3. 正如我在您的问题下的评论中对 Bergi 所说的那样,在 EL 执行几乎每个 JS 脚本/回调之后,实际上会访问微任务检查点。所以,是的,EL 本身有一些调用站点,但其中大多数实际上来自 https://html.spec.whatwg.org/multipage/webappapis.html#clean-up-after-running-script (2认同)