JavaScript作为单线程运行的脚本语言,本身无法同时处理多个任务,事件循环机制就是它实现异步操作的核心方案。在事件循环的运行过程中,微任务和宏任务的执行顺序直接决定了异步代码的输出结果,是前端开发必须掌握的核心知识点。

事件循环的基本运行逻辑
JavaScript的代码执行过程分为同步任务和异步任务两部分,同步任务会直接进入主线程执行栈依次执行,而异步任务则会被放到任务队列中等待。当主线程的执行栈清空之后,事件循环会从任务队列中读取任务放入执行栈执行,这个循环的过程就是事件循环。
任务队列中的异步任务又被分为宏任务队列和微任务队列,两者的执行优先级不同,微任务的执行优先级始终高于宏任务。
宏任务与微任务的常见类型
宏任务(Macrotask)
常见的宏任务包含以下几类:
- script整体代码
- setTimeout定时器回调
- setInterval定时器回调
- DOM事件回调
- ajax请求回调
- setImmediate(仅Node环境支持)
- requestAnimationFrame(仅浏览器环境支持)
微任务(Microtask)
常见的微任务包含以下几类:
- Promise的then、catch、finally回调
- async函数执行后返回的Promise的回调
- process.nextTick(仅Node环境支持,优先级高于其他微任务)
- MutationObserver回调(仅浏览器环境支持)
执行顺序规则
事件循环中微任务和宏任务的执行遵循以下固定规则:
- 首先执行同步任务,遇到宏任务将其放入宏任务队列,遇到微任务将其放入微任务队列
- 同步任务执行完成后,依次执行当前所有微任务队列中的任务,直到微任务队列清空
- 微任务队列清空后,从宏任务队列中取出第一个任务执行,执行过程中遇到新的微任务继续放入微任务队列
- 该宏任务执行完成后,再次执行当前所有微任务队列中的任务,循环往复直到所有任务执行完毕
代码示例演示
下面通过几个不同场景的代码示例来验证执行规则:
基础执行顺序示例
// 同步任务
console.log('同步任务1');
// 宏任务 setTimeout
setTimeout(() => {
console.log('宏任务setTimeout1');
}, 0);
// 微任务 Promise.then
Promise.resolve().then(() => {
console.log('微任务Promise.then1');
});
// 同步任务
console.log('同步任务2');
上述代码的执行结果为:
同步任务1 同步任务2 微任务Promise.then1 宏任务setTimeout1
执行过程解析:首先执行两个同步任务输出前两个结果,同步任务完成后执行微任务队列中的Promise回调,最后执行宏任务队列中的setTimeout回调。
嵌套任务执行示例
console.log('同步任务开始');
setTimeout(() => {
console.log('宏任务setTimeout1');
// 宏任务中嵌套微任务
Promise.resolve().then(() => {
console.log('宏任务中的微任务Promise.then1');
});
}, 0);
Promise.resolve().then(() => {
console.log('微任务Promise.then1');
// 微任务中嵌套宏任务
setTimeout(() => {
console.log('微任务中的宏任务setTimeout1');
}, 0);
});
console.log('同步任务结束');
上述代码的执行结果为:
同步任务开始 同步任务结束 微任务Promise.then1 宏任务setTimeout1 宏任务中的微任务Promise.then1 微任务中的宏任务setTimeout1
执行过程解析:同步任务执行完成后先执行微任务Promise.then1,该微任务中嵌套的宏任务被放入宏任务队列。之后执行第一个宏任务setTimeout1,其内部的微任务被放入微任务队列,当前宏任务执行完成后,执行微任务队列中的该微任务,最后执行宏任务队列中剩余的setTimeout回调。
async/await相关示例
async函数执行时,await之前的代码属于同步任务,await后面的代码会被作为微任务放入微任务队列。
async function asyncFunc() {
console.log('async函数内同步代码');
await Promise.resolve();
console.log('await后面的微任务代码');
}
console.log('外层同步代码1');
asyncFunc();
console.log('外层同步代码2');
上述代码的执行结果为:
外层同步代码1 async函数内同步代码 外层同步代码2 await后面的微任务代码
执行过程解析:外层同步代码1先执行,然后执行async函数,函数内await之前的代码是同步任务,输出对应内容,await后面的代码被转为微任务放入队列,之后执行外层同步代码2,同步任务全部完成后执行微任务队列中的await后续代码。
实际开发注意事项
理解微任务和宏任务的执行机制后,在实际开发中可以避免很多逻辑问题:
- 不要过度依赖setTimeout的延迟时间为0,因为它的回调是宏任务,执行时机一定晚于当前同步任务和微任务
- Promise的then回调是微任务,适合处理需要优先于其他宏任务执行的异步逻辑
- 在Node环境中process.nextTick的微任务优先级高于Promise.then,需要注意两者的执行顺序差异
- 复杂的异步逻辑中可以通过梳理同步任务、微任务、宏任务的执行顺序来预判代码运行结果,减少调试成本
JavaScript事件循环微任务宏任务执行机制修改时间:2026-07-21 23:24:31