JavaScript Event Loop机制详解:宏任务与微任务的执行顺序
本文深入解析JavaScript单线程模型下的Event Loop机制,详细区分宏任务(Macro-task)与微任务(Micro-task)的定义与执行时机。通过具体代码示例,阐明同步代码、异步微任务及宏任务的执行优先级,解释为何await后的代码与Promise会在定时器之前执行,帮助开发者掌握异步编程的核心逻辑。
JavaScript Event Loop机制详解:宏任务与微任务的执行顺序
首先观察以下代码片段:
async function (){
await f2()
console.log('f1')
}
async function f2(){
console.log('f2')
}
console.log('正常1')
f1()
setTimeout(()=>{
console.log('定时器')
})
console.log('正常2')
该段代码预期的正确输出顺序依次为:正常1、f2、正常2、f1、定时器。
造成上述输出顺序的原因是什么?
JavaScript单线程模型与任务分类
JavaScript是一门单线程语言,尽管HTML5引入了Web-Worker,但JavaScript核心的单线程特性并未改变。由于是单线程执行,其运行模式类似于只有一个窗口的银行,客户必须排队依次办理业务,同理JavaScript的任务也必须按顺序逐一执行。若某个任务耗时过长,后续任务将被阻塞等待,因此产生了同步任务与异步任务的区分。
基本概念
除了广义的同步与异步任务概念外,对任务类型可进行更细致的分类。
- 宏任务(macro-task):包括整体代码script、setTimeout、setInterval。
- 微任务(micro-task):包括Promise、process.nextTick。
宏任务执行机制:浏览器为了确保JS内部的task与DOM任务有序执行,会在一个task执行结束后、下一个task执行开始前,对页面进行重新渲染(即task->渲染->task的循环过程)。
例如,鼠标点击触发事件回调需要执行一个宏任务,随后解析HTML。
微任务机制:微任务通常指在当前同步任务执行结束后立即执行的任务,例如对一系列动作做出反馈,或执行无需分配新任务的异步操作,以此降低性能开销。
明确概念后,我们再次分析代码的执行流程。
async function (){
await f2()
console.log('f1')
}
async function f2(){
console.log('f2')
}
console.log('正常1')
f1()
setTimeout(()=>{
console.log('定时器')
})
console.log('正常2')
代码执行流程与输出顺序解析
执行流程分析
首先执行正常的同步流程,打印出“正常1”。接着执行f1()函数,由于f1内部包含await,await后面的f2()会立即执行,因此打印“f2”。随后继续执行同步代码,打印“正常2”。此时同步任务全部结束,开始执行异步队列中的微任务。await f2()等待f2()方法执行完毕后,继续执行后续代码打印“f1”。最后执行宏任务队列中的setTimeout,打印“定时器”。
这就是“正常1”和“正常2”打印在“f1”之前的原因,因为所有微任务执行时,当前执行栈的代码必须已执行完毕。而“f2”和“f1”打印在“定时器”之前,是因为所有微任务总会在下一个宏任务之前全部执行完毕。
以上为本文的全部内容,希望对您的学习有所帮助,也欢迎大家继续支持本站。
D3.js 比例尺与坐标轴的配置详解
2026-11-05 16:54:46
JavaScript怎么遍历对象的Symbol键和不可枚举属性
2026-11-05 13:13:39
封装一个健壮的JS字符串判空工具函数
2026-11-05 12:16:14
JavaScript合并数组的三种常用方法:concat、扩展运算符与push
2026-11-05 11:22:29
JavaScript立即执行函数(IIFE)是什么及基本语法
2026-11-05 10:51:19
