首页 > 解决方案 > 浏览器中的事件循环如何同时处理事件队列、作业队列、渲染队列?

问题描述

上周我开始使用 nodejs 学习 Javascript 后端。在使用async函数时,我想从各个方面了解这一点,并开始研究这个主题。
在 jsconf 中找到了 Jake Archibald 的演示文稿,并试图了解什么是事件循环以及事件循环如何在不同的队列中运行以及它可以处理哪些队列。

我认为本演示文稿中的一张图表非常有助于理解所有内容。

链接视频的截图

但我想知道事件循环如何处理由承诺回调组成的作业队列。
我们可以为这个队列添加另一个路由到这个图中吗?

显示 3 个循环标记的图表. (我试图将它实现到图中:))

我想知道的另一个问题是,事件循环对渲染队列有什么作用?事件循环是否将其发送到另一个地方?因为我们知道事件循环将事件队列或作业队列中的函数发送到 javascript 引擎中的调用堆栈来运行这些。
但是渲染队列有请求动画帧和其他样式元素。
事件循环是否将请求动画帧部分发送到 javascript 引擎并将其他布局、样式和绘制部分发送到布局引擎?

标签: javascriptasynchronouspromisecallbackevent-loop

解决方案


这张图是对事情如何工作的过度简化,要详细了解会发生什么,我邀请您直接查看规范,这些规范实际上已经变得非常易读且易于导航。

从那里你会看到

[t]任务队列不是任务队列。

如果我们自己走过度简化的道路,只用我们感兴趣的东西来解释事件循环例程,

  • 来自其他进程和先前任务的消息将在各种任务源中排队新任务,它们本身以更少的任务队列结束。(这提供了 Jake 图表的左循环)。
  • 在每次迭代中,事件循环的第一步是从这些任务队列中的一个中选择第一个任务(根据需要选择,这允许任务优先级)。
  • 在这个主要任务完成后(规范中的第 7 步),事件循环将在所谓的microtask -checkpoint中查看微任务队列。
  • 仅对于自上次迭代以来活动显示监视器确实发出其 SYNC 脉冲的文档(在 60Hz 监视器上每 16.67 毫秒一次),它会更新渲染(Jake 图中的右循环,规范中的步骤 11.6~11.15)。
  • 在这些步骤中,它将执行一些任务,例如触发 UI 事件、更新动画和运行动画帧回调。每次这些算法调用回调时,用户代理必须根据运行后清理算法执行新的 任务检查点,因此例如每个动画帧回调都会与这样的检查点交错,其中一些算法甚至直接执行微任务检查点。

所以这意味着microtask-checkpoint不只是在事件循环中的单个点执行,它在主任务之后执行一次,并且在更新渲染步骤中的每个回调执行之后执行很多次。

用户代理不能仅仅延迟微任务,它必须在排队的任务完成后立即执行,即从事件循环的角度来看,微任务是同步执行的。

同样,“渲染队列”也不是任务队列,它必须在浏览器有“渲染机会”时运行,它不能成为任务优先级机制的一部分(更多here)。


因为我们知道事件循环将事件队列或作业队列中的函数发送到 javascript 引擎中的调用堆栈来运行这些。

不完全是。首先要记住,javascript 执行只是浏览器执行的一部分,许多任务根本不涉及 javascript,例如,即使您确实从 web 浏览器中禁用了 javascript,事件循环仍然必须运行,它仍然必须更新渲染,它仍然必须发送表单,它仍然必须对网络事件做出反应,例如加载媒体等。
事件循环所做的是运行任务的步骤,但这些可能有很多不同东西,他们可能不一定会在任何地方发送任何东西。

此外,规范并没有说明计算应该如何分布,但关于渲染,我们可以假设简而言之,从更新渲染到第 14 步的所有内容都应该在同一个进程上完成(它必须按顺序运行),但是步骤 15(“更新渲染”)实际上将所有内容绘制到监视器可以(我认为它在所有现代浏览器中)传递给另一个进程,专门用于此渲染任务。
您可以查看Chromium 的文档,解释它们如何管理浏览器进程和渲染器之间的相互通信。


推荐阅读