JavaScript事件循环决定代码执行顺序:同步代码→微任务(Promise.then、async/await)→宏任务(setTimeout);输出A→D→B→C是因微任务在本轮宏任务后立即执行,宏任务需等待下一轮循环。

JavaScript 事件循环不是“机制教程”,而是你代码执行顺序失控时,真正该去查的底层原因。
为什么 setTimeout(fn, 0) 不是立刻执行
它被扔进宏任务队列,必须等当前所有同步代码 + 所有微任务跑完才轮到它。浏览器不会因为设了 0 就插队——它只认队列优先级,不认你的心情。
- 同步代码(如
console.log)直接入调用栈,立刻执行 -
Promise.resolve().then()进微任务队列,本轮宏任务结束后马上清空 -
setTimeout进宏任务队列,要等到下一轮事件循环才取一个出来
Promise.then 和 async/await 都走微任务队列
它们不是“更快的异步”,而是“更早的回调”——await 后面的代码会被编译成微任务,所以总比 setTimeout 先输出。
console.log('A');
Promise.resolve().then(() => console.log('B'));
setTimeout(() => console.log('C'), 0);
console.log('D');
输出一定是 A → D → B → C,不是因为你写错了,是事件循环铁律。
立即学习“Java免费学习笔记(深入)”;
调试时怎么看出任务在哪个队列里
别猜,用 console + 断点 + 调用栈观察最可靠:
- 在 Chrome DevTools 中打个断点,暂停后看 Call Stack 是否为空
- 再看 Console 输出顺序:如果某句 log 出现在同步代码之后、但又在
setTimeout之前,大概率是微任务 - 想强制插入微任务?用
queueMicrotask(() => {...}),比 Promise 包一层更干净
事件循环没有魔法,只有队列和顺序。真正难的不是理解它,而是在封装库、动画帧、状态更新交织时,一眼识别出哪段逻辑被卡在了宏任务尾巴上。











