javascript事件循环按“一宏→清微→一宏→清微”节奏执行:先运行一个宏任务,再立即执行所有当前微任务(含新加入的),之后才取下一个宏任务;同步代码必先完成,settimeout即使为0也属宏任务,promise.then属微任务,故输出顺序为1→4→3→2。

JavaScript 的事件循环是单线程环境下实现异步非阻塞执行的核心机制。它不靠多线程,而是靠“排队 + 优先级调度”来协调同步代码、微任务和宏任务的执行顺序。
调用栈清空是事件循环启动的前提
所有同步代码都在调用栈中按顺序执行,函数压栈、返回弹栈。只有当调用栈彻底为空时,事件循环才开始介入——它不会打断正在运行的函数,也不会提前执行队列里的任务。
- 哪怕 setTimeout 设为 0,回调也绝不会在同步代码中途插入
- console.log、函数调用、变量赋值等都属于同步操作,必须逐条完成
- 调用栈未空,微任务和宏任务一律等待
微任务总在宏任务之间“插队”执行
每次调用栈清空后,事件循环会立即检查微任务队列,并一次性执行完所有已存在的微任务(包括执行过程中新加入的),之后才去取下一个宏任务。
- 常见微任务:Promise.then/catch/finally、queueMicrotask、MutationObserver 回调
- 微任务可以链式触发:一个 Promise.then 里再 new Promise,其 then 仍属本轮微任务
- 它不抢占当前宏任务,但会在该宏任务结束、下个宏任务开始前“清场”
宏任务按队列顺序逐个取出执行
宏任务每次只取一个,执行完毕后再次清空微任务队列,再取下一个宏任务。这个“一宏 → 清微 → 一宏 → 清微”的节奏构成完整循环。
- 常见宏任务:整体 script 脚本、setTimeout/setInterval、I/O 回调、DOM 事件、requestAnimationFrame
- setTimeout 的回调进入的是宏任务队列,不是立即执行,也不是紧随上一个宏任务
- 用户点击、页面渲染(浏览器环境)也作为宏任务参与调度,有固定时机
执行顺序口诀与典型流程
一次完整循环的执行步骤是:执行一个宏任务 → 执行所有当前微任务 → (可选)浏览器渲染 → 执行下一个宏任务。
- 初始宏任务通常是整个 script 标签内的代码
- 遇到 Promise.resolve().then(),回调进微任务队列;遇到 setTimeout,回调进宏任务队列
- 例如:console.log(1); setTimeout(() => console.log(2), 0); Promise.resolve().then(() => console.log(3)); console.log(4); 输出为 1 → 4 → 3 → 2
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











