译:Node.js事件循环的动画指南

137 阅读3分钟

众所周知,JavaScript和Node.js是单线程的,但实际上这意味着什么呢?

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

我们都曾尝试从那个缓慢的网站上抓取数据,或者在获得数据库查询结果之前等待了30多秒。我们是否想因为数据库查询速度慢而阻止单线程执行更多任务?幸运的是,Node.js并没有停止运行其他操作,因为Libuv是一个C++库,负责事件循环和一部处理诸如网络请求、DNS解析、文件系统操作、数据加密等任务。

当Node.js处理诸如数据库查询之类的任务时,幕后会发生什么?我们将按照这段代码一步一步来探索它。

image.png

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

在我们的示例中,代码行console.log('Starting Node.js')被添加到调用栈并将Starting Node.js打印到控制台。通过这样做,它到达日志函数的末尾并从调用栈中弹出。

m2ja8tymo646or3emo07.gif

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

l2vxqbfq6r7e55up4bnz.gif

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

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

5dnrdqoql3sp9rw0gt1x.gif

示例代码请参考:github.com/fabrilallo/…

事件循环小测验

image.png

1sV8nGA.gif

总结

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

在文章中,我们看到了Libuv的重要作用以及它处理许多潜在的长时间运行任务的能力。同时,我们了解了事件循环以及其作为I/O事件队列中异步操作回调与调用栈之间的桥梁(或连接器)的作用。在接下来的文章中,我们将更加详细地探讨事件循环的不同阶段如何处理计时器、I/O、promises和ticks。

原文链接

dev.to/nodedoctors…

相关工具

latentflip.com/loupe