# 九.事件环

前言

事件循环中的异步队列有两种:macro(宏任务)队列和 micro(微任务)队列

  • macro-task:常见的有 setTimeout、setInterval、 setImmediate、script(整体代码)、 I/O 操作、UI 渲染等。
  • micro-task:常见的有 process.nextTick、Promise、MutationObserver 等。

# 1.Event Loop 过程

  • 初始状态:调用栈空。micro 队列空,macro 队列里有且只有一个 script 脚本(整体代码)。
  • 全局上下文(script 标签)被推入调用栈,同步代码执行。在执行的过程中,通过对一些接口的调用,可以产生新的 macro-task 与 micro-task,它们会分别被推入各自的任务队列里。同步代码执行完了,script 脚本会被移出 macro 队列,这个过程本质上是队列的 macro-task 的执行和出队的过程
  • 接着处理的是 micro-task。但需要注意的是:当 macro-task 出队时,任务是一个一个执行的;而 micro-task 出队时,任务是一队一队执行的。因此,我们处理 micro 队列这一步,会逐个执行队列中的任务并把它出队,直到队列被清空。
  • 执行渲染操作,更新界面
  • 检查是否存在 Web worker 任务,如果有,则对其进行处理

(上述过程循环往复,直到两个队列都清空)

# 2.渲染的时机

假如我想要在异步任务里进行 DOM 更新,我该把它包装成 micro 还是 macro 呢

setTimeout(task, 0) // macro:script --> micro --> render --> macro --> render
1
Promise.resolve().then(task) // micro:script --> micro --> render
1

对比发现,当我们需要在异步任务中实现 DOM 修改时,把它包装成 micro 任务是相对明智的选择