关于 Node.js®
作为异步事件驱动的 JavaScript 运行时,Node.js 被设计用于构建可扩展的网络应用程序。在以下“hello world”示例中,可以同时处理许多连接。在每个连接上,回调都会被触发,但如果没有工作要做,Node.js 将进入休眠状态。
const { createServer } = require('node:http');
const hostname = '127.0.0.1';
const port = 3000;
const server = createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World');
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
这与当今更常见的并发模型形成对比,在该模型中使用的是操作系统线程。基于线程的网络效率相对较低,而且非常难以使用。此外,Node.js 用户无需担心进程死锁,因为没有锁。Node.js 中几乎没有函数直接执行 I/O,因此进程永远不会阻塞,除非使用 Node.js 标准库的同步方法执行 I/O。由于没有阻塞,因此在 Node.js 中开发可扩展系统非常合理。
如果其中一些语言不熟悉,可以阅读关于 阻塞与非阻塞 的完整文章。
Node.js 在设计上类似于 Ruby 的 Event Machine 和 Python 的 Twisted 等系统,并受其影响。Node.js 将事件模型更进一步。它将事件循环作为运行时结构而不是库来呈现。在其他系统中,始终存在阻塞调用来启动事件循环。通常,行为是在脚本开头通过回调定义,并在最后通过阻塞调用(如 EventMachine::run()
)启动服务器。在 Node.js 中,没有这样的启动事件循环调用。Node.js 在执行完输入脚本后直接进入事件循环。当没有更多回调要执行时,Node.js 退出事件循环。这种行为类似于浏览器 JavaScript——事件循环对用户隐藏。
HTTP 是 Node.js 中的一等公民,其设计考虑了流和低延迟。这使得 Node.js 非常适合作为 Web 库或框架的基础。
Node.js 的设计没有线程,但这并不意味着您不能利用环境中的多个核心。可以使用我们的 child_process.fork()
API 生成子进程,并且这些子进程的设计易于通信。基于相同的接口构建了 cluster
模块,它允许您在进程之间共享套接字,从而实现跨核心负载均衡。