在一些关于JavaScript异步行为的在线资源中,也提到了浏览器架构、调用栈、事件循环和事件队列等概念。在描述浏览器事件循环的工作原理时,有些人使用“事件队列”,而其他人则使用“回调队列”。我对这些术语感到困惑,想知道它们是否指的是在浏览器中使用的同一队列数据结构,或者它们是否不同并用于处理不同的情况?图1 - 图2 -
在HTML的命名法中(它定义了浏览器的事件循环),两者都是不正确的。我们拥有的是"任务源", 它们可以映射到不同的任务队列。 在事件循环处理开始时,用户代理将从哪个任务队列中选择执行下一个任务。这个任务本身可能会触发事件或调用回调函数。这些任务通过各种方式排队,可以作为其他任务的一部分(例如,在任务并行工作后,当并行工作完成时,它将要求排队一个任务),也可以直接从IPC消息中触发(例如用户启动的事件)。还请注意,有一个事件循环的部分,在其中回调被调用并且事件直接由事件循环触发,而不是来自任务:更新渲染。 在那里,您会找到一个回调映射和各种事件(滚动、调整大小、媒体查询等),作为事件循环中这个特殊位置的一部分调用,该位置本身只会偶尔被调用(通常在监视器发送V-Sync信号时)。
在回调队列中,任务被广泛地分为两类,即微任务和宏任务(通常称为任务)。 宏任务在以下情况下被添加到宏任务队列中: 执行新的JavaScript程序或子程序(例如从控制台或通过在元素中运行代码)。 事件触发,将事件的回调函数添加到宏任务队列中。 达到使用setTimeout()或setInterval()创建的超时或间隔,导致相应的回调被添加到任务队列中。 微任务是一个短小的函数,在创建它的函数或程序退出后执行,并且仅当JavaScript执行堆栈为空时才执行,但在返回控制权给用户代理用于驱动脚本执行环境的事件循环之前执行。微任务仅来自我们的代码。它们通常由Promise创建:.then/catch/finally处理程序的执行成为微任务。微任务也被“await”使用,因为它是Promise处理的另一种形式。在文献中,您经常会看到将宏任务称为任务,将微任务称为作业。