javascript事件循环自动运行,无需手动触发;主线程空闲时,引擎先清空微任务队列(如promise回调),再执行一个宏任务(如settimeout回调),如此循环。

主线程代码执行完毕后,JavaScript 引擎会自动进入事件循环(Event Loop)的检查阶段,无需手动触发。只要调用栈(call stack)为空,事件循环就会开始轮询任务队列(macrotask queue)和微任务队列(microtask queue),按规则取出并执行任务。
微任务优先于宏任务执行
每次主线程同步代码执行完后,引擎会立即清空当前所有微任务(如 Promises 回调、queueMicrotask、MutationObserver),再取下一个宏任务(如 setTimeout、setInterval、I/O、UI 渲染)。
- 微任务队列在每次宏任务结束后立即执行,且会持续清空直到为空
- 宏任务每次只取一个,执行完再重新检查微任务队列
- 例如:Promise.resolve().then(...) 会在当前同步代码结束后立刻运行,比 setTimeout(..., 0) 更早执行
宏任务是事件循环的“调度单位”
事件循环本身不主动“启动”,而是由宿主环境(浏览器或 Node.js)在主线程空闲时驱动。常见宏任务来源包括:
将一个或多个视频上传至YouTube。当用户想“上传到YouTube”“发YouTube”“批量上传”“upload to YouTube”“post videos to YouTube”或发布到YouTube时使用此技能。
- 全局脚本执行(初始同步代码)
- setTimeout / setInterval 到期回调
- DOM 事件(如 click、input)被触发后入队
- fetch 响应、WebSocket 消息等异步 I/O 完成
- 浏览器中的一帧渲染(render task)也是宏任务的一部分
没有“手动触发事件循环”的 API
开发者不能也不需要显式调用类似 runEventLoop() 的方法。事件循环是运行时底层机制,完全自动:
- 写 setTimeout(fn, 0) 不是“触发循环”,而是把 fn 推入宏任务队列,等待下一轮循环取用
- 使用 queueMicrotask(fn) 是确保 fn 在本轮同步代码结束后、下次宏任务开始前执行
- 即使主线程空闲,事件循环仍持续运行——它始终在监听任务队列和微任务队列是否非空
注意:Node.js 与浏览器的细微差异
两者事件循环结构不同(Node.js 有 timer、pending callback、idle/prepare、poll、check、close callback 六个阶段),但对开发者而言表现一致:
- 同步代码 → 执行所有微任务 → 进入下一宏任务阶段
- process.nextTick()(Node.js 特有)优先级高于 Promise 微任务,但仍在当前操作之后、下一轮宏任务之前
- 浏览器中没有 nextTick,但可用 queueMicrotask 达到类似效果










