javascript的事件循环是什么_它如何管理任务队列?

JavaScript事件循环是异步非阻塞核心机制,按“执行宏任务→清空微任务队列→可选UI渲染→取下一宏任务”流程调度;宏任务(如setTimeout)每轮一个,微任务(如Promise.then)在宏任务后全部执行完毕。

JavaScript 的事件循环(Event Loop)是它实现异步非阻塞特性的核心机制,负责协调执行栈、任务队列(宏任务与微任务)以及调用 API 的时机。它不“管理”队列本身,而是按固定规则轮询和调度队列中的任务。

宏任务与微任务的区分

事件循环把异步任务分为两类:

  • 宏任务(Macrotask):包括整体脚本、setTimeoutsetIntervalsetImmediate(Node.js)、I/O 回调、UI 渲染等;每次事件循环只执行一个宏任务。
  • 微任务(Microtask):包括 Promise.then/catch/finallyMutationObserverqueueMicrotask();在每个宏任务执行完后,会清空整个微任务队列(即全部执行完,直到为空)。

事件循环的基本流程

一次完整的循环步骤如下:

  • 执行当前宏任务(如主脚本或某个定时器回调)
  • 执行过程中遇到 Promise 等,将对应的 then 回调推入微任务队列
  • 宏任务执行完毕,立即执行所有排队的微任务(逐个取出并执行,期间新加入的微任务也会被本轮执行)
  • 微任务队列清空后,浏览器可能进行一次 UI 渲染(如果需要)
  • 从宏任务队列中取出下一个任务(如 setTimeout 回调),开始下一轮

任务队列不是先进先出的简单队列

宏任务队列实际由多个来源组成,优先级不同:

  • HTML 规范定义了不同类型的任务源(如 DOM 操作、网络、定时器),但具体执行顺序由宿主环境决定
  • setTimeout(fn, 0) 并不意味着立刻执行,而是“至少延迟 0ms”,实际要等当前宏任务 + 所有微任务完成,并等到下一次事件循环才可能执行
  • 微任务队列始终具有更高优先级——它总是在宏任务之间插入执行,且不会被渲染或 I/O 中断

常见误区提醒

几个容易混淆的点:

  • Promise.resolve().then() 是微任务,setTimeout(() => {}, 0) 是宏任务,二者嵌套时微任务总比同层宏任务先运行
  • 多个 Promise.then 链式调用会依次加入微任务队列,按注册顺序执行
  • Node.js 中还有 process.nextTick(),它的优先级高于所有微任务(包括 Promise),但仅限 Node 环境