贝利信息

什么是事件循环_JavaScript中宏任务和微任务如何执行

日期:2026-01-05 00:00 / 作者:紅蓮之龍
JavaScript事件循环每次执行一个宏任务后立即清空当轮微任务队列;宏任务包括setTimeout、I/O、UI渲染等,微任务包括Promise.then、queueMicrotask、MutationObserver等;执行顺序为同步代码→微任务→下一轮宏任务。

JavaScript 的事件循环不是“先执行宏任务再执行微任务”这么简单,而是每次从宏任务队列取一个任务执行完后,**立即清空当前轮次的微任务队列**——这个“清空”动作才是理解执行顺序的关键。

宏任务和微任务分别有哪些

宏任务(macrotask)是事件循环调度的基本单位,每次只取一个执行;微任务(microtask)则在每个宏任务结束后、渲染前集中执行,且必须全部执行完才能进入下一个宏任务。

执行顺序:为什么 setTimeout(setTimeout(...)) 不等于嵌套延迟

宏任务之间严格按插入顺序排队,但微任务会插在两个宏任务之间“挤占”执行时机。比如连续两次 setTimeout,哪怕第二个在第一个回调里注册,它也得等第一个宏任务执行完 + 所有微任务跑完 + 下一轮事件循环开始,才能执行。

console.log(1);
setTimeout(() => console.log(2), 0);
Promise.resolve().then(() => console.log(3));
console.log(4);

输出是 1432。注意:第 3 行的 Promise.then 是微任务,它被推入微任务队列;第 2 行的 setTimeout 是宏任务,排在下一轮事件循环开头。

微任务嵌套不会导致无限循环阻塞 UI

即使在 Promise.then 里反复调用 queueMicrotask 或返回新 Promise,它们都会被加入当前轮次的微任务队列末尾,但事件循环仍会在该轮次结束后退出微任务执行,去检查是否需要渲染或处理下一个宏任务——所以不会饿死主线程。

实际调试时怎么确认任务类型

不能只看函数名,要看它**注册时所处的上下文以及宿主环境实现**。例如:

最可靠的方式是写个最小测试用例,用 console.log 打点,配合浏览器 DevTools 的 “Event Loop” 面板或 Node.js 的 --trace-event 观察实际调度顺序。