什么是 NodeJS?服务器端 JavaScript 详解

发布: (2026年5月3日 GMT+8 04:07)
14 分钟阅读
原文: Dev.to

Source: Dev.to

介绍

大家好,开发者朋友们!如果你花时间构建过网页应用,你可能已经听说过 Node.js 的热潮。如果还没有,请查看我之前的博客,我会一步步带你从零开始构建你的第一个基础 Node.js 服务器:Setting Up Your First Node.js Application

什么是 Node.js,为什么它会爆炸式流行?

在本文中,我们将从头开始探讨 Node.js:

  • 它的起源
  • 它是如何打破 “JavaScript 只能在浏览器中运行” 的壁垒
  • 它的核心架构
  • 为什么它会成为后端开发的游戏规则改变者

无论你是想从前端转向全栈的开发者,还是正在探索新工具的后端工程师,阅读完本文后,你都能获得更多信息并获得全新的视角。

注意: 本文基于一些基础概念。如果你想更深入地了解内部实现(例如 Node.js 架构的三大支柱、事件循环的各个阶段,或线程池),请查看我之前的文章:

Node.js 之前的生态

JavaScript 于 1995 年创建,主要用于为网页添加交互性(最初称为 LiveScript)。它在浏览器沙箱中运行,负责 DOM 操作、用户事件、表单验证和网络请求。

与此同时,服务器端则由 Perl、PHP、Java、RubyPython 等语言主导。这种分工在当时是合乎情理的:

浏览器端服务器端
轻量级、事件驱动的脚本语言强大的 I/O、安全性、系统级访问
在沙箱中运行在操作系统上运行
处理 UI 和用户交互处理数据存储、业务逻辑、API

开发者必须在不同语言之间切换:前端使用 JavaScript,后端使用其他语言。这导致逻辑重复、开发速度变慢以及技能碎片化。

Ryan Dahl的愿景 (2009)

在开发高性能网络应用时,Ryan Dahl 对传统的服务器模型感到沮丧。像 Apache 这样的工具采用 每请求一个线程(thread‑per‑request)方式:每个进入的连接都会产生一个新的线程或进程。这在低流量时还能勉强工作,但在高并发下扩展性差,原因包括:

  • 上下文切换开销
  • 高内存使用
  • 阻塞 I/O(例如等待数据库查询)会使整个线程停滞

Ryan 想要一个能够提供:

  1. 非阻塞支持
  2. 针对 I/O 密集型工作负载的高效性(实时应用、聊天、流媒体)
  3. 端到端使用同一种语言

他尝试了多个运行时后,最终选择了 Google 的 V8 JavaScript 引擎(刚刚开源且速度极快)。2009 年 11 月,他发布了 Node.js —— 一个基于 V8、libuv 和 C++ 绑定构建的运行时,使 JavaScript 能在服务器上以事件驱动、非阻塞 I/O 模型运行。

关键说明:
JavaScript 是编程语言(ECMAScript)。
Node.js 是提供在浏览器之外执行 JavaScript 环境的运行时。

什么是 Node.js?

Node.js 是一个 开源、跨平台的 JavaScript 运行时,基于 Chrome 的 V8 引擎构建。它在浏览器之外执行 JavaScript 代码,使服务器端脚本成为可能。

  • V8 负责 JavaScript 的解析、即时编译(JIT)和执行。
  • libuv 提供缺失的功能:文件系统访问、网络、定时器以及跨平台的异步 I/O 层。

类比

  • JavaScript → 汽车引擎
  • 浏览器 → 时尚跑车(针对 UI 进行优化)
  • Node.js → 坚固卡车(针对搬运货物:服务器 I/O、数据库、API 进行优化)

V8 – 引擎内部工作原理

Google 的 V8 是用 C++ 编写的高性能 JavaScript 和 WebAssembly 引擎。它使用 即时编译(JIT) 在运行时将 JavaScript 转换为优化后的机器码。

亮点

功能描述
解析与优化隐藏类、内联缓存、先进的垃圾回收机制
速度在许多任务中接近原生的性能
限制单独的 V8 对文件、网络或操作系统一无所知——这正是 Node.js 添加其层的地方

Node.js 嵌入 V8,并通过 C++ 绑定和 libuv 为跨平台异步 I/O 提供支持。

核心架构:事件驱动、非阻塞 I/O

Node.js 采用基于 libuv 事件循环和线程池的事件驱动、非阻塞 I/O 模型。

  • 事件循环 – 持续检查调用栈和任务队列,在操作完成后执行回调。
  • 线程池 – 将某些阻塞任务(例如 DNS 查询、繁重的文件 I/O)卸载到线程池,从而保持主事件循环的非阻塞。默认池大小为 4 个线程(可通过 process.env.UV_THREADPOOL_SIZE 配置)。

工作原理

  1. 为慢操作(数据库查询、文件读取、HTTP 请求)注册回调
  2. 继续执行 – 主线程继续处理其他事件。
  3. 当操作完成时,libuv 发出事件,已注册的回调被执行。

大多数 JavaScript 代码在主线程上运行;线程池只处理少数真正会阻塞的操作。这种设计非常适合 I/O 密集型应用,但对 CPU 密集型任务需要谨慎处理(在现代 Node.js 中使用 worker threads)。

浏览器 JS 与 Node.js 执行

方面浏览器 JavaScriptNode.js
全局对象window, document, fetch, WebSocketglobal, process, require, fs, http
APIDOM、CSSOM、Web API文件系统、网络、流、子进程
事件循环由浏览器引擎管理由 libuv 管理
模块ES 模块(import)(或旧的 script 标签)CommonJS(require)和 ES 模块
使用场景UI 渲染、客户端交互服务器端逻辑、API、实时服务

Node.js 运行时架构概览

+-------------------+      +-------------------+
|   JavaScript      |      |   C++ Bindings    |
|   (V8 Engine)     |  |   (libuv)         |
+-------------------+      +-------------------+
          ^                         ^
          |                         |
          |   Event Loop & Thread   |
          |   Pool (libuv)          |
          +-------------------------+
                    |
          +-------------------+
          |   OS / System     |
          +-------------------+

为什么开发者纷纷转向 Node.js

传统模型(例如 PHP)Node.js 模型
同步(默认)。每个请求通常会生成一个新进程或线程(Apache、Nginx + PHP‑FPM)。异步(默认)。单线程通过事件循环处理大量并发连接。
阻塞 I/O 会使整个进程停滞。非阻塞 I/O 使线程保持空闲以处理其他工作。
多语言 需要用于前端(JS)和后端(PHP、Ruby 等)。单语言(JavaScript)端到端,减少上下文切换和重复逻辑。
每个请求更高的内存占用更低的内存使用——事件循环使用小堆即可处理大量连接。

结束语

Node.js 不仅仅是“服务器端的 JavaScript”。它是一个精心构建的环境,将浏览器式的事件处理带到后端,使得使用单一语言栈即可构建高度可扩展、I/O 密集型的应用程序。

如果你刚刚入门,可以尝试一个简单的 HTTP 服务器:

// hello.js
const http = require('http');

const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('Hello, Node.js!\n');
});

server.listen(3000, () => {
  console.log('Server running at http://localhost:3000/');
});

使用以下命令运行它:

node hello.js

从这里你可以探索丰富的 npm 包生态系统,深入了解事件循环内部实现,或使用 WebSocket 构建实时应用。祝编码愉快!

PHP(阻塞模型)

  • 适用于简单的动态页面。
  • 对并发连接的效率较低 – 阻塞调用会占用资源。

Java(线程模型)

  • 对于具有强大线程支持和成熟库的企业工作负载表现出色。
  • 管理线程、回调或响应式框架会增加复杂性和开销。

Node.js (事件‑驱动模型)

功能好处
单线程事件循环思维模型更简单,竞争条件更少。
非阻塞 I/O以低内存使用处理成千上万的并发连接。
前后端统一语言(JS/TS)开发更快,代码/类型可共享。
通过 npm 的庞大生态系统最大的包注册表,数不清的可复用模块。

采纳驱动因素

  • 实时应用随着 WebSockets(聊天、实时更新、流媒体)成为主流。
  • 全栈 JavaScript 减少了开发者的上下文切换。
  • 微服务和 API 更青睐轻量、可扩展的运行时。
  • PayPal、Uber 和 Netflix 等公司在采用 Node.js 后报告了巨大的性能和生产力提升。

注意: Node.js 并非在所有场景都是最佳工具(如视频编码等 CPU‑密集型任务可能更适合 Go 或 Java),但在合适的场景下表现出色。

常见使用场景

  • RESTful API: Express、Fastify、NestJS。
  • 实时应用: WebSockets(Socket.io、原生 ws)、协作工具、游戏后端。
  • 流媒体与微服务: Netflix 将其用于边缘逻辑和数据处理。
  • CLI 工具: npm、webpack 以及无数开发工具都是用 Node.js 构建的。
  • 物联网与边缘服务器: 轻量足迹在受限设备上运行良好。
  • 无服务器: AWS Lambda、Vercel 等都喜欢 Node.js 的快速冷启动。

为什么 Node.js 很重要

Node.js 不仅把 JavaScript 带到了服务器——它 让后端开发大众化,并证明了简单的事件驱动模型能够驱动全球最大规模的应用。通过解决 Ryan Dahl 最初的痛点,结合 V8 的速度和 libuv 的优雅,它创建了一个运行时,具备:

  • 高生产力 – 快速原型和迭代。
  • 可扩展性 – 用最少资源处理海量并发。
  • 有趣 – 直观的异步模式和充满活力的社区。

曾被视为浏览器“玩具”语言的 JavaScript,如今因 Node.js 成为 全栈强力引擎。统一的生态系统、活跃的社区以及持续的改进(工作线程、ESM 支持、更佳性能)使其在 2026 年及以后 仍然保持相关性。

入门

  1. nodejs.org 安装 Node.js。

  2. 验证安装:

    node -v
    npm -v
  3. 使用内置的 http 模块创建一个简单的 HTTP 服务器:

    // server.js
    const http = require('http');
    
    const server = http.createServer((req, res) => {
      res.writeHead(200, { 'Content-Type': 'text/plain' });
      res.end('Hello, Node.js!\n');
    });
    
    server.listen(3000, () => {
      console.log('Server running at http://localhost:3000/');
    });
  4. 运行它:

    node server.js
  5. 探索 ExpressNestJS 等框架,尝试 async/await,并深入了解事件循环——真正的 “啊哈” 时刻就在这里。


你对 Node.js 有什么经验?
你是从 PHP/Java 迁移过来,还是在构建你的第一个全栈 JS 应用?在评论中留下你的想法。如果你喜欢这篇概览,请分享或查看上面链接的更深入的架构文章。

编码愉快! 🚀

参考文献

  • 官方 Node.js 文档
  • Ryan Dahl 的演讲
  • V8 博客
  • libuv 文档
  • 社区资源(npm、GitHub、博客)
0 浏览
Back to Blog

相关文章

阅读更多 »

自己制作框架,有什么建议吗?

《Making my own framework》的封面图片。有什么建议吗?https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fde...