JavaScript 事件循环的工作原理是什么?
描述 JavaScript 事件循环的机制及其工作原理。
事件循环(Event Loop)是 JavaScript 中处理异步任务的核心机制,它让单线程环境能够高效运行非阻塞代码而不占用主线程。整个架构包含以下关键组件:
-
JavaScript 单线程特性:
JavaScript 基于单个主线程运行所有代码,无法同时并行执行任务。为避免同步操作阻塞用户交互(如 UI 渲染响应被阻塞导致页面卡顿),通过事件循环实现了异步处理方式。 - 运行时组件:
- 调用栈 (Call Stack):LIFO 结构,按顺序执行同步函数。例如:
function first() { console.log('start'); } function second() { setTimeout(handleTimeout, 0); } first(); second();
其中
first()
先压栈运行,后压栈second()
触发。 - 任务队列 (Task Queue / Callback Queue):存放宏任务的回调函数队列,如
setTimeout
、setInterval
、UI 事件监听回调等。 - 微任务队列 (Microtask Queue):专门存放高优先级的微任务回调,如
Promise.then()
。 - 事件循环本体 (Event Loop):持续轮询检测调用栈是否为空。一旦栈空,优先检查并清空微任务队列中的所有回调将其推入调用栈执行;最后若有任务待处理,弹出一个宏任务队列中的函数推入调用栈。。
- 调用栈 (Call Stack):LIFO 结构,按顺序执行同步函数。例如:
- 事件循环工作流程示例:
- 代码依次推入调用栈运行同步部分;
- 遇到宏任务(如
setTimeout
)时将回调添加到宏任务队列; - 新产生的微任务会进入独立的微任务队列;
- 调用栈空后:
- 所有已排队的微任务将被连续取出执行;
- 然后才执行一个宏任务回调;
- 这个过程循环重复直到队列清空。
模拟代码预测输出序列:
console.log('脚本启动'); setTimeout(() => console.log('来自宏任务队列的函数'), 0); Promise.resolve().then(() => console.log('来自微任务队列的函数')); console.log('脚本结束');
结果打印顺序:
脚本启动 脚本结束 来自微任务队列的函数 来自宏任务队列的函数
- 应用优势与重要性:
通过此机制可优化页面执行流畅性,尤其在高负载 I/O 相关操作(AJAX API 调取结果被优先置于微任务后处理以优先完成异步链)。