JavaScript事件循环通过分层调度和严格优先级维持单线程流畅性,将任务分为“立刻干”“马上干”“稍后干”三类;调用栈是唯一执行同步代码的后进先出结构。

JavaScript 事件循环不是“等任务做完再处理”,而是靠分层调度+严格优先级维持单线程不卡顿。它不靠多线程并发,靠的是把任务拆成“立刻干”“马上干”“稍后干”三类,再按固定节奏轮流交班。
调用栈:唯一正在干活的“执行员”
所有同步代码都在这里逐行运行,后进先出——函数调用压栈,返回弹栈。一旦某段代码死循环或耗时过长(比如 while(Date.now() ),整个栈就被堵住,页面立刻冻结。这不是事件循环失效,而是它根本没机会启动:只要栈不空,它就一直等着。
- 栈容量有限,递归过深会触发“Maximum call stack size exceeded”错误
- 它不存储异步回调,只管当前正在执行的函数帧
- 浏览器渲染、用户输入事件也得排队等它清空才能被处理
微任务队列:宏任务结束后的“加急插队权”
Promise.then、queueMicrotask、MutationObserver 回调全进这里。它的特点是:当前宏任务一结束,立刻清空整个微任务队列,中间不穿插任何新宏任务。这意味着连续十个 Promise.then 会一口气执行完,不会被 setTimeout 打断。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 哪怕在 setTimeout 回调里 new Promise().then(...),这个 then 也会排在当前 setTimeout 执行完之后、下一个宏任务开始之前
- DOM 变动后想立即读取更新后的布局(如 offsetHeight),用 queueMicrotask 比 setTimeout(0) 更可靠
- 过度嵌套 microtask(比如在 then 里不断 new Promise)可能延迟渲染,引发视觉卡顿
宏任务队列:浏览器调度的“主日程表”
包括 script 脚本本身、setTimeout/setInterval 回调、I/O 完成通知、UI 渲染帧、用户点击事件等。它们按进入顺序排队,但每次只取一个执行——执行完,先清微任务,再取下一个宏任务。
立即学习“Java免费学习笔记(深入)”;
- setImmediate(Node.js)和 requestIdleCallback(浏览器)也属于宏任务,但优先级更低
- 一次宏任务执行期间产生的新宏任务(如又调了 setTimeout),要等到下一轮循环才可能执行
- 浏览器通常每 16ms 强制插入一次渲染任务(如果需要),这也算一个宏任务
事件循环的真实节奏:不是“轮询”,而是“接力”
它没有定时器 ticking,而是一个持续判断的流程:栈空 → 执行一个宏任务 → 栈空 → 清空全部微任务 → 栈空 → 下一个宏任务 → ……中间任何一步没完成,后续就卡住。所以“setTimeout(0)”实际延迟远不止 0ms,它至少要等完当前宏任务 + 所有微任务 + 可能的渲染任务。
- 网络请求 onload 是宏任务;fetch().then() 是微任务——这就是为什么 fetch 总比 XMLHttpRequest 快半拍
- 鼠标点击事件是宏任务,但 click 事件处理器里 Promise.then 仍是微任务,会紧接在 click 处理完后执行
- Node.js 的 process.nextTick 属于微任务,但优先级略高于 Promise.then,在同一轮中更早执行

















