深入理解JavaScript事件循环:宏任务与微任务的执行机制

作者:纸飞机时间:2026-10-23 21:29:36浏览:322

本文深入解析JavaScript的事件循环(Event Loop)机制,详细阐述同步任务、宏任务(MacroTask)与微任务(MicroTask)的区别与执行顺序。通过剖析Promise、async/await及定时器的行为,揭示主线程、任务队列与微任务队列的交互逻辑,帮助开发者掌握异步代码的执行规律。

首先观察以下代码片段:

事件循环 Event Loop

这段代码的控制台打印顺序究竟是如何确定的?

正确的输出顺序为:script start, script end, promise1, promise2, setTimeout。

这一结果涉及核心概念:事件循环(Event Loop)、宏任务(MacroTask)以及微任务(MicroTask)。

事件循环 Event Loop

一、事件循环 Event Loop

JavaScript引擎通常维护两个线程:一个是负责执行代码的“主线程”,另一个是负责处理主线程与其他进程(主要是各类I/O操作)通信的“Event Loop线程”,也可称为消息线程。

根据执行方式,所有任务可划分为两类:同步任务(Synchronous)和异步任务(Asynchronous)。

同步任务是指在主线程上按顺序排队执行的任务,必须等待前一个任务完全执行完毕后,才能开始执行下一个任务。

异步任务则不直接进入主线程,而是进入“任务队列”(Task Queue)。只有当任务队列通知主线程该异步任务可以执行时,它才会被推入主线程执行。

通常情况下,异步任务主要包含以下三种类型:

1、普通事件,例如click、resize等交互事件。

事件循环 Event Loop

2、资源加载事件,例如load、error等。

事件循环 Event Loop

3、定时器功能,包括setInterval和setTimeout。

事件循环 Event Loop

事件循环的具体工作流程如下:

  • 同步任务直接加入主线程执行,而异步任务则注册到Event Table中。
  • 当异步任务执行完成后,Event Table会将对应的回调函数移入Event Queue。
  • 当主线程内的任务执行完毕,即执行栈变为空时,系统会去Event Queue中读取对应的函数,并将其推入主线程执行。
  • 上述过程会不断重复,这就是所谓的Event Loop(事件循环)。

宏任务与微任务

二、宏任务与微任务

在JavaScript中,任务被进一步细分为两种:宏任务(MacroTask)和微任务(MicroTask)。

2.1 MacroTask(宏任务)

宏任务由宿主环境(如浏览器和Node.js)提供。

常见的宏任务包括:整个script全部代码、setTimeout、setInterval。

为了确保JS内部任务与DOM渲染有序执行,浏览器会在每个task执行结束后、下一个task开始前,对页面进行重新渲染(即task -> 渲染 -> task...的模式)。

2.2 MicroTask(微任务)

微任务由语言标准定义。

常见的微任务包括:Promise、await。

async函数表示函数内部可能包含异步方法。当async方法执行时,遇到await会立即执行其后的表达式,并将await表达式后面的代码放入微任务队列,从而让出执行栈给同步代码先执行。


async function foo() {
  var a = await new Promise((resolve) => {
    setTimeout(() => {
      resolve(1);
    }, 2000);
  });
  console.log(a); // 第2秒时输出: 1
}
foo();

2.3 宏任务与微任务的执行顺序:

  • 当执行栈执行完所有同步任务后,系统会检查执行栈是否为空。如果为空,则进一步检查微任务队列是否为空。若微任务队列为空,则执行宏任务;否则,将一次性执行完所有微任务。
  • 每次单个宏任务执行完毕后,系统会检查微任务队列是否为空。如果不为空,则按照先入先出的规则全部执行完微任务后,将微任务队列置为null,然后再执行下一个宏任务,如此循环。

总结:执行顺序遵循 同步 -> 微任务 -> 宏任务 的规则。

事件循环 Event Loop

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

作者最新文章