事件循环

事件循环

Event Loop

JS 是单线程的。在 JavaScript 引擎里,取 task 和执行 task 的代码封装在一个死循环里面,JavaScript 引擎等待 tasks 的出现,有则执行,无则 sleep异步任务分为宏任务微任务

Macro Task 宏任务

宏任务示例:<script>setTimeoutsetIntervalsetImmediaterequestAnimationFrameI/OUI 渲染

Micro Task 微任务

微任务示例:process.nextTickPromisesqueueMicrotaskMutationObserver

Micro is like macro but with higher priority.

Event Loop 算法

while (true) {
    // 执行宏任务
    let task = macroTaskQueue.getOldestTask();
    execute(task);

    // 执行微任务
    while (microTaskQueue.length > 0) {
        execute(microTaskQueue.getOldestTask())
    }

    // 渲染
    if (isRenderTime()) {
        render();
    }
}

Node EventLoop vs 浏览器 EventLoop

microtask执行时机不同。

Node.js 的 EventLoop 分为 6 个阶段

  • timers: 执行 setTimeoutsetInterval
  • I/O callbacks: 处理上一轮剩下来的少数未执行的 I/O 回调
  • idle, prepare: Node 内部使用
  • poll 阶段:获取新的 I/O 事件, 适当的条件下 node 将阻塞在这里
  • check 阶段:执行 setImmediate() 的回调
  • close callbacks 阶段:执行 socketclose 事件回调

浏览器环境下,microtask 的任务队列是每个 macrotask 执行完之后执行。而在 Node.js 中,microtask 会在事件循环的各个阶段之间执行,也就是一个阶段执行完毕,就会去执行 microtask 队列的任务:

参考