拥有多个(宏)任务队列可以实现任务优先级。例如,用户代理(UA)可以选择将用户事件(例如单击事件)优先于网络事件,即使后者实际上是由系统首先注册的,因为前者可能对用户更加可见并需要更低的延迟。在HTML中,这是通过
Event Loop's Processing model的第一步允许的,该步骤规定UA必须从其任务队列之一中选择要执行的下一个任务。(注意:HTML规范不要求存在多个队列,但它们定义了多个
task sources以保证类似任务的执行顺序)。那么,为什么还需要另一个称为
microtask queue的东西呢?我们可以找到一些早期关于“如何”实现它的讨论,但我没有深入挖掘谁最初提出了这个想法以及用例是什么。
然而,从
讨论 我发现的 中可以看出,有几个需要这种机制的提案正在进行中:
- 变异观察器
- 现已弃用的ES
Object.observe()
- 当时即将推出的 ES Promises
- 同样是当时即将推出的,但我不知道为什么要引用它 ES WeakRefs
- HTML自定义元素回调
前两个也是浏览器中首先实现的,我们可以大概说,它们的使用情况是实现这种新类型队列的主要原因。
两者实际上做了类似的事情:它们监听对象(或DOM树)上的更改,并将在作业期间发生的所有更改合并为单个事件
(不要读作Event)。
有人可能会认为,此事件可以排队到下一个(宏)任务中,具有最高优先级,但事件循环已经有点复杂了,并且并非每个作业都必须来自
任务。
例如,
渲染实际上是每个事件循环迭代的一部分,只是大多数时间它会提前退出,因为现在不是渲染的时间。
因此,如果您在渲染帧期间进行DOM修改,则可以使修改被渲染,在整个渲染完成后才获得回调。
由于观察者的主要用例是在观察到的更改触发性能重负副作用之前对其进行操作,因此我想您可以看出,在执行修改的作业之后立即插入回调的方法是必要的。
PS:那时我对事件循环并不了解,我离规范还很远,可能在这个答案中加入了一些年代错误的东西。
Object.observe
,类似于 MutationObserver,它将各种事件合并为单个回调。他们还预见到即将推出的 ES Promises、ES WeakRefs(不确定为什么)和 HTML Custom Elements 回调,这些都需要微任务队列。同时请注意,还有多个(宏)任务来源。 - Kaiido