有人可以解释一下 Nodejs 单线程是如何异步的吗

Pra*_*yap 2 javascript asynchronous node.js

我读过

\n
\n

Node.js 是单线程的,即它以单个顺序或方向执行代码。在给定时间,仅执行单个任务/调用。异步和\n单线程:执行不会\xe2\x80\x99等待当前请求完成\n并移至下一个请求/调用。

\n
\n

我对单线程和异步这两个感到困惑。那么,当一个任务是 setTimeout、另一个任务是从 API 获取数据、其他任务是一些算术运算时,如果我执行一些操作序列,那么流程是如何处理的?那么考虑到它是单线程的,操作顺序是怎样的呢?

\n

jfr*_*d00 9

在这种情况下,“单线程”意味着它在单个线程中运行您的 Javascript。这意味着它会运行一段 Javascript,直到将控制权返回给系统,然后才能运行附加到其他事件的代码。Javascript 中没有两部分实际上是同时执行的。

仅供参考,出于讨论的目的,我们在这里忽略了 WorkerThreads,它是运行 Javascript 多线程的有目的的方式,但不涉及一般的异步架构。

异步操作全部由nodejs以本机代码(通常是C/C++代码)实现。它们是诸如计时器、网络操作、磁盘操作等之类的东西......本机代码(主要在名为 的跨平台库中libuv)具有 Javascript 中的接口,允许您调用它们,例如http.request()fs.read(),但这些的底层核心实现函数是本机代码。这些操作的本机代码在其实现中可能实际使用操作系统线程,也可能不使用操作系统线程。但是,这些线程对 Javascript 代码来说是完全隐藏的。

例如,nodejs 中的网络操作不使用线程。它们在操作系统中使用本机异步 API,允许它们在网络操作完成时收到通知,而无需阻塞或旋转并等待。其他异步操作(例如文件操作)实际上使用本机操作系统线程池来“模拟”异步体系结构。

因此,当您的 Javascript 作为单线程运行时,可以同时处理多个异步操作。如果你看一下这段代码:

const fsp = require('fs').promises;

Promise.all([fsp.readFile("filea.txt"), fsp.readFile("fileb.txt")]).then(results => {
   console.log(results[0]);
   console.log(results[1]);
}).catch(err => {
   console.log(err);
});
Run Code Online (Sandbox Code Playgroud)

这将并行读取两个文件,并告诉您两个文件中的数据何时可用。虽然 JavaScript 仍然作为单线程运行,但底层文件操作正在使用操作系统级线程,而磁盘操作则在单独的线程中运行。因此,只有实际的 Javascript 是单线程的,而不一定是底层的异步操作。

幸运的是,您通常可以完全避免多线程编程的并发问题,因为您自己的 Javascript 的两部分永远不会同时运行。因此,您不需要互斥体或其他并发设备来安全地写入变量。线程使用的细节被抽象在异步接口后面。而且,nodejs 如何处理这些异步接口的完成的事件驱动性质决定了,在处理包含下一个异步结果的下一个完成事件之前,将运行一段 Javascript 来完成。