Node.js 动画:事件循环

2025-05-27

Node.js 动画:事件循环

我们都听说过 JavaScript 和 Node.js 是单线程的,但从实际意义上讲这意味着什么?

这意味着 JavaScript 一次只能做一件事。例如,我们不能同时对数字进行乘法和加法运算。我们通常按顺序进行运算。我们先加,然后乘,反之亦然。现代计算机速度很快,两个或多个连续任务的结果看起来像是同时计算的,但也有例外。

我们都曾尝试从某个速度缓慢的网站抓取数据,或者等待超过三十秒才能获得数据库查询的结果。我们是否想因为数据库查询速度慢而阻止单线程执行更多任务?幸运的是,Node.js 不会因为 Libuv 而停止运行其他操作。Libuv 是一个 C++ 库,负责事件循环并异步处理网络请求、DNS 解析、文件系统操作、数据加密等任务。

Node.js 在执行诸如数据库查询之类的任务时,其底层发生了什么?我们将逐步遵循这段代码来探索它。

展示事件循环的代码示例

V8 JavaScript 引擎管理着一个调用栈,它是一个追踪程序哪个部分正在运行的重要部分。每当我们调用一个 JavaScript 函数时,它都会被推送到调用栈。一旦函数到达其末尾或某个return语句,它就会从调用栈中弹出。

在我们的示例中,代码行 console.log('Starting Node.js') 被添加到调用堆栈并打印 Starting Node.js 到控制台。这样,它就到达了log函数的末尾并从调用堆栈中移除。

Node.js 调用堆栈上的函数调用

下面这行代码是一个数据库查询。由于这些任务可能需要很长时间,因此会被立即弹出。它们会被传递给 Libuv,Libuv 会在后台异步处理这些任务。与此同时,Node.js 可以继续运行其他代码,而不会阻塞其单线程。

将来,Node.js 会知道如何处理查询,因为我们已将回调函数与处理任务结果或错误的指令关联起来。在我们的例子中,它是一个简单的 console.log,但在生产应用程序中,它可能是复杂的业务逻辑或数据处理。

Libuv 处理 I/O 操作

当 Libuv 在后台处理查询时,我们的 JavaScript 不会被阻止并可以继续运行 console.log(”Before query result”)

在 Node.js 运行我们的代码时处理 I/O

查询完成后,其回调会被推送到 I/O 事件队列,以便稍后运行* *事件循环将队列与调用堆栈连接起来。它会检查后者是否为空,并移动第一个队列项进行执行。

事件循环检查是否为空调用堆栈

代码可在https://github.com/fabrilallo/event-loop-1获取。

事件循环小测验

尝试弄清楚以下代码在控制台上打印什么。

展示事件循环的更复杂的代码示例

事件循环的动画指南

结论

事件循环、委托和异步处理机制是 Node.js 的秘密武器,它可以处理数千个连接、读取/写入巨型文件、处理计时器,同时处理代码的其他部分。

在本文中,我们了解了 Libuv 的重要作用及其处理大量可能长时间运行的任务的能力。同时,我们还了解了事件循环及其作为 I/O 事件队列中异步操作回调与调用堆栈之间的桥梁/连接器的作用。在接下来的文章中,我们将更详细地探讨事件循环不同阶段如何处理计时器I/O承诺滴答。

如果您喜欢这篇文章,请在 Twitter 上关注我们@fabriziolallo@andrewhu368

文章来源:https://dev.to/nodedoctors/an-animated-guide-to-nodejs-event-loop-3g62
PREV
如何在本地安装 DeepSeek Janus Pro 7B?
NEXT
精彩的编程项目创意及其获取途径(适合初学者的版本)