JS事件循环:别被那些所谓的“异步”术语给忽悠了

在北京极客 中级 6小时前 更新于 2026年7月26日 44 浏览 8 点赞 约 2 分钟

很多人把 JavaScript 吹成单线程、非阻塞、异步并发,听起来很高大上,但如果你真去问 V8 引擎,它可能会告诉你它只认得调用栈(Call Stack)和内存堆(Memory Heap),至于什么事件循环、回调队列,它压根不关心。

这就是最反直觉的地方:让 JS 具备异步能力的“事件循环”,根本就不是 JS 语言本身的一部分,而是由运行环境(浏览器或 Node.js)提供的。

想搞清楚为什么 setTimeout(fn, 0) 竟然不会立即执行,或者为什么 Promise 总是抢在定时器前面运行,得先认清这个底层逻辑:

单线程 = 只有一个调用栈 = 一次只能干一件事。

JS事件循环:别被那些所谓的“异步”术语给忽悠了

如果 JS 真的在等待一个 API 请求返回,整个页面就直接卡死了。为了解决这个问题,运行环境(比如浏览器的 Web APIs 或 Node.js 的 libuv)接管了耗时操作。

所谓的事件循环,本质上就是一个没完没了的 while 循环,逻辑简单到离谱:

let eventLoopQueue = [];

![JS事件循环:别被那些所谓的“异步”术语给忽悠了](/uploads/articles/d2c5bafb0a7f2e5f.jpg)

while (true) { 
  // 每一个循环周期被称为一个 "Tick"
  if (eventLoopQueue.length > 0) {
    // 只要调用栈空了,就从队列里抓一个任务扔进去执行
    let nextTask = eventLoopQueue.shift(); 
    nextTask(); 
  }
}

这个机制把 JS 变成了个“调度员”。当你调用 setTimeout 时,JS 并不是在计时,而是告诉浏览器:“帮我计时 1 秒,时间到了把这个回调函数扔进队列里。”

这时候 JS 继续执行后面的代码,直到调用栈清空,事件循环才会把那个回调函数从队列里拉回来执行。

这里有个关键的实战细节:不同环境的异步实现完全不同。

  • 浏览器端: 由浏览器内核提供 Web APIs(如 fetch, setTimeout)。
  • Node.js 端: 依赖 C++ 编写的 libuv 库来处理文件系统、网络等底层异步操作。
JS事件循环:别被那些所谓的“异步”术语给忽悠了

所以,别再把事件循环当成某种神秘的魔法,它就是一个在后台不停检查“栈是否为空”的死循环。
AI编程AI编程实战nodeprogrammingjavascript

全部回复 (4)

脚本小子小柯 专家 9小时前
其实浏览器API才在后面干活,V8确实只管执行。
0 回复
程序员Tom 高级 9小时前
那宏任务和微任务的优先级,也是浏览器那边控制的吗?
0 回复
杭漂码农 专家 9小时前
@程序员Tom 基本是,不过不同环境实现有细微差别,你是在刷面试题吗?
0 回复
架构师老刘 中级 9小时前
以前死磕Promise执行顺序,后来发现看浏览器源码才明白。
0 回复

发表回复

支持 Markdown 格式