宏任务、微任务和Event Loop

139 阅读2分钟

前言

  我在学习Event Loop时看了大量的文章,那些文章都写的很好,但是往往是每篇文章有那么几个关键的点,很多篇文章凑在一起综合来看,才可以对这些概念有较为深入的理解。

  于是,我在看了大量文章之后,结合自己的理解表达出来。希望大家可以通过这篇文章,了解到Event Loop到底是一种什么机制。如果在文中出现书写错误的地方,欢迎大家一起探讨。

Event Loop(事件循环)是什么

  Event Loop是一个执行模型,为了协调事件、用户交互、脚本、渲染、网络等,用户代理必须使用本节中描述的事件循环。每个代理都有一个关联的事件循环,这是该代理独有的。

参考文档 HTML Standard (whatwg.org)

To coordinate events, user interaction, scripts, rendering, networking, and so forth, user agents must use event loops as described in this section. Each agent has an associated event loop, which is unique to that agent.

Event Loop(事件循环)包含什么概念

Event Loop有一个或多个任务队列。任务队列是一组任务。

  • 微任务队列不是任务队列

宏队列和微队列

宏队列,macrotask,也叫tasks。  一些异步任务的回调会依次进入macro task queue,等待后续被调用,这些异步任务包括:

  • setTimeout
  • setInterval
  • setImmediate (Node独有)
  • requestAnimationFrame (浏览器独有)
  • ajax (网络请求)
  • DOM 事件 (click、blur等)
  • I/O
  • UI rendering (浏览器独有)

微队列,microtask,也叫jobs。  另一些异步任务的回调会依次进入micro task queue,等待后续被调用,这些异步任务包括:

  • process.nextTick (Node独有)
  • Promise
  • Object.observe
  • MutationObserver

Event Loop 执行

JavaScript代码的具体流程:

  1. 执行全局Script同步代码,这些同步代码有一些是同步语句,有一些是异步语句(比如setTimeout等)
  2. 全局Script代码执行完毕后,调用栈Stack会清空
  3. 从微队列microtask queue中取出位于队首的回调任务,放入调用栈Stack中执行,执行完后microtask queue长度减1
  4. 继续取出位于队首的任务,放入调用栈Stack中执行,以此类推,直到直到把microtask queue中的所有任务都执行完毕。注意,如果在执行microtask的过程中,又产生了microtask,那么会加入到队列的末尾,也会在这个周期被调用执行
  5. microtask queue中的所有任务都执行完毕,此时microtask queue为空队列,调用栈Stack也为空
  6. 取出宏队列macrotask queue中位于队首的任务,放入Stack中执行
  7. 执行完毕后,调用栈Stack为空
  8. 重复第3-7个步骤

可以参考视频 2分钟了解 JavaScript Event Loop | 面试必备_哔哩哔哩_bilibili