深入理解JavaScript Event Loop:宏任务与微任务的执行顺序

作者:后端茶话

时间:2026-10-23

浏览:105

本文解析JavaScript单线程模型下的Event Loop机制,区分浏览器与Node.js环境差异。详细阐述宏任务(如setTimeout)与微任务(如Promise)的队列特性及执行优先级,结合Node.js中timers与setImmediate的时序关系,通过代码示例说明事件循环的具体运行步骤。

文章目录

环境判断与Event Loop阶段

在深入探讨执行机制前,首先需要明确当前代码运行的环境是浏览器还是Node.js。

区分这两种环境的一个简单方法是观察全局对象。在Node.js环境中,全局变量window未定义,但setImmediate函数已被定义;而在浏览器环境中,情况则相反,setImmediate通常未定义。

Node.js的Event Loop包含多个阶段,其中timer阶段专门负责处理setTimeout和setInterval回调函数的执行。

check阶段则用于执行通过setImmediate注册的回调函数。

宏任务与微任务的分类及特性

从任务分类来看,宏任务(Macro Task)主要包括初始执行的script代码块、setTimeout、setInterval、I/O操作以及UI交互事件(如点击事件)。

微任务(Micro Task)则包括Promise相关的回调、process.nextTick以及Promise().then()中注册的函数。

在队列管理上,宏任务可以存在多个不同的任务队列。

相比之下,微任务始终只维护一个单一的队列。

对于setTimeout等定时器任务,其推迟执行的毫秒数越小,该任务在队列中的排序就越靠前,从而更早被调度执行。

值得注意的是,在Node.js环境中,timer阶段(处理setTimeout和setInterval)的执行优先级高于check阶段(处理setImmediate)。


setTimeout(() => {
  console.log('setTimeout')
},0);  // 大于1000时,会先执行setImmediate
setImmediate(()=> { console.log('setImmediate')})

console.log('start');
setTimeout(function (){
  console.log('timeout');
},10);
new Promise((resolve) => {
  console.log('promise');
  resolve()
  setTimeout(() => {
    console.log('Promsie中的setTimeout');
  },0);
}).then(() => {
  console.log('then');
});
console.log('end');

事件循环运行机制详解

以下是JavaScript事件循环的核心运行机制:

第一步,JavaScript引擎在执行栈中执行一个宏任务。

在执行过程中,如果遇到微任务,则将其添加到微任务队列中等待处理。

当当前宏任务执行完毕后,引擎会立即清空并执行微任务队列中的所有任务。

微任务队列执行完毕后,系统会检查是否需要渲染页面,此时GUI线程接管进行渲染工作。

渲染完成后,JavaScript线程重新接管控制权,开启下一次事件循环,从事件队列中取出下一个宏任务继续执行。

以上即为JavaScript Event Loop机制的核心内容,希望这些解析能帮助大家更好地理解单线程模型下的异步执行逻辑。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章