深入理解JavaScript中的宏任务和微任务机制

作者:异步漫步

时间:2026-10-26

浏览:648

本文深入解析JavaScript单线程模型下的Event Loop机制,详细区分宏任务与微任务的执行优先级。通过定时器、Promise回调及queueMicrotask()等实例,阐明调用栈、任务队列与微任务队列的交互流程,帮助开发者准确掌握异步代码的执行顺序与原理。

文章目录

引言

// 开启一个定时器 1秒后执行
setTimeout( () => {
    console.log(1)
}, 1000)
console.log(2)

上述代码在控制台输出的结果为“2,1”,即先输出数字2,随后输出数字1。具体执行顺序为:首先执行打印“2”的代码,接着执行定时器中设定1秒后打印“1”的逻辑。

// 开启一个定时器 1秒后执行
setTimeout( () => {
    console.log(1)
}, 0)
console.log(2)

若将定时器中的时间参数修改为0,即立即触发,控制台输出结果依然保持为“2, 1”。这是因为定时器的作用是经过指定间隔后,将回调函数放入任务队列中;而“console.log(2)”则直接在调用栈中同步执行。只有当调用栈中的代码执行完毕后,消息队列中的定时器任务才会被移入调用栈并执行。

宏任务与微任务

宏任务队列

引言

微任务队列

引言

栈与调用栈

JavaScript采用单线程模型,其运行依赖于事件循环机制(Event Loop)。

调用栈

栈

栈是一种数据结构,遵循后进先出(LIFO)原则,类似于弹夹中子弹最后压入却最先射出的特性。

调用栈用于存放当前正在执行或等待执行的代码片段。

代码在栈中按照从上到下的顺序依次执行,即最后进入栈的代码最先被执行。

消息队列(任务队列)

队列是一种数据结构,遵循先进先出(FIFO)原则,类似于排队打饭时排在前面的人优先获得服务。

队列中存放的是即将被执行的异步代码或回调函数。

当调用栈中的同步代码执行完毕后,引擎会检查消息队列,并按照顺序将队列中的代码依次移入调用栈中执行。

在JavaScript中,任务队列主要分为两种类型。

宏任务队列

大部分常规代码及异步操作(如定时器、I/O操作)会在宏任务队列中排队等待。

微任务队列

Promise对象的回调函数(包括then、catch、finally方法)会被放入微任务队列中排队。

整体执行流程

  • 首先执行调用栈中的同步代码。
  • 当前宏任务执行完毕后,立即执行微任务队列中的所有任务。
  • 微任务清空后,再开始执行下一个宏任务。
// 开启一个定时器 1秒后执行
setTimeout( () => {
    console.log(1)
}, 0)
Promise.resolve(1).then(() => {
    console.log(2)
})
//全局作用域的代码一定是位于栈中的
console.log(3)

上述代码的执行结果为“3 2 1”。打印“3”的语句位于全局作用域,属于同步代码,因此直接位于调用栈中并最先执行。

Promise的执行原理

  • 当执行Promise时,then方法相当于为Promise注册了一个回调函数。
  • 当Promise的状态从pending(进行中)变为fulfilled(已成功)时,then注册的回调函数会被放入微任务队列中等待执行。

queueMicrotask()函数用于手动向微任务队列中添加一个任务。

// 开启一个定时器 1秒后执行,在宏任务队列中等待
setTimeout( () => {
    console.log(1)
}, 0)
// 在微任务队列中等待
Promise.resolve(1).then(() => {
    console.log(2)
})
// 在为任务队列中
Promise.resolve().then(()=> {
    console.log(3)
})

执行结果为“2 3 1”。其中“2”和“3”均位于微任务队列中,而“1”位于宏任务队列中。根据Event Loop机制,应先执行微任务。由于微任务队列遵循“先进先出”原则,“2”先进入队列因此先被移出到调用栈运行,接着是“3”,最后才执行宏任务中的“1”。

// 在微任务队列中等待
Promise.resolve(1).then(() => {
    setTimeout( () => {
        console.log(1)
    }, 0)
})
// 在为任务队列中
Promise.resolve().then(()=> {
    console.log(3)
})

执行结果为“3 1”。虽然定时器外层包裹在微任务的Promise中,且外层Promise先执行,但由于内部包含定时器,该定时器随后进入宏任务队列。此时,“3”处于微任务中,会直接移入调用栈执行,因此最终输出结果为“31”。

至此,关于深入理解JavaScript中宏任务和微任务机制的介绍已完成。如需了解更多JS中的宏任务和微任务相关内容,请搜索本站以前的文章或继续浏览下面的相关文章,希望大家以后多多支持本站!

实用工具推荐

电子包浆

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

使用 ›
图片压缩

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

使用 ›
相关文章