关键在于任务队列类型:同步代码最先执行;promise.then是微任务,本轮宏任务结束后立即执行;settimeout回调是宏任务,需等同步代码和所有微任务完成后才执行。

关键不在“谁快谁慢”,而在于它们被放进不同队列:Promise 的 .then 是微任务,必须在当前宏任务结束后、下一个宏任务开始前全部执行完;setTimeout 的回调是宏任务,哪怕延时为 0,也得等当前宏任务走完 + 微任务清空 + 新一轮事件循环启动后才执行。
同步代码永远最先运行
所有同步语句从上到下立即执行,不等待任何异步操作。比如:
-
console.log('1')和console.log('4')是同步的,立刻输出 -
new Promise((resolve) => { console.log('2'); resolve(); })中的console.log('2')也是同步的 -
setTimeout调用本身是同步的,但它的回调不会此时执行
微任务在本轮末尾集中清空
同步代码执行完毕、调用栈清空后,引擎立刻检查并执行所有待处理的微任务,中途不插入宏任务。常见微任务包括:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
-
Promise.then/catch/finally回调 -
async/await后续代码(本质也是 Promise 微任务) queueMicrotask()- MutationObserver(浏览器环境)
宏任务每次只取一个,排队按顺序
微任务队列彻底清空后,事件循环才从宏任务队列中取出第一个任务执行。典型宏任务有:
-
setTimeout和setInterval的回调 - 整个
<script></script>标签内容(初始宏任务) - I/O 回调、UI 渲染、用户点击事件
requestAnimationFrame
setTimeout(fn, 0) 不代表“立刻”,只是尽快注册——它仍受最小延迟约束(通常 ≥4ms),且必须等同步 + 微任务全部完成才能触发。
快速判断某段逻辑属于哪类任务
不用背顺序,靠机制推导更稳:
- 如果代码写在
.then()、await后面、或调用了queueMicrotask(),就是微任务 - 如果代码是
setTimeout、setInterval、click事件回调、或fetch成功后的.then()外层回调,就是宏任务 - 在
setTimeout回调里写的Promise.then,那个.then属于“下一个宏任务里的微任务”,要等这个setTimeout执行完再清空
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










