六维教程

Node.js 是什么

这篇回答一个基础问题,JavaScript 是怎么从浏览器跑到服务器上的。你会看到浏览器里的 JS 和 Node.js 里的 JS 有什么不同,Node.js 能做什么,以及它和其他后端语言差在哪里。搞清楚这些背景,后面学 fs、http 这些模块才不会一头雾水。

JavaScript 原本只在浏览器里

你之前学的 JavaScript 其实由两部分组成,一个是语言核心,一个是运行环境给的额外能力。

ECMAScript 语言核心

ECMAScript 是 JS 的语言标准,定义了变量声明、运算符、流程控制、函数、对象、数组、类这些基础语法。这部分和运行环境无关,浏览器和服务器里写法完全一样。

const sum = (a, b) => a + b;
console.log(sum(2, 3));   // 浏览器和 Node.js 里输出都是 5

浏览器提供的 Web API

除了语言核心,浏览器还给 JS 塞了一批独有对象,比如操作页面的 document、控制浏览器窗口的 window、获取浏览器信息的 navigator。这些 API 依赖浏览器环境才能存在。

// 这段代码只有在浏览器里才能跑
console.log(window);      // 浏览器的全局对象
console.log(document);    // 当前页面的文档对象
console.log(navigator);   // 浏览器信息,比如版本、语言

在浏览器里,window 是全局对象,console.log 会打开控制台面板。这些都是浏览器给的,语言核心本身并不包含。

Node.js 的诞生

2009 年,Ryan Dahl 把 Chrome 浏览器的 V8 引擎单独拿出来,配上文件系统、网络等一批服务端 API,做出了 Node.js。JavaScript 第一次可以离开浏览器,在服务器上直接运行。

这个思路解决了一个老问题,以前写后端要换一门语言,比如 PHP 或 Java,现在前后端可以都用 JS,一套语法走到底。同时 Node.js 也带火了 npm 这个包生态,2010 年 npm 随 Node.js 一起发布,社区贡献的代码飞速增长,如今已经是全球最大的开源软件仓库。

什么是运行时

运行时(runtime)指程序运行所需的环境总称,包括执行代码的解释器或引擎,以及配套的内置 API。浏览器是一个运行时,它提供 DOM 给 JS 用。Node.js 是另一个运行时,它提供文件系统和网络能力给 JS 用。

两者的关系可以这么记,ECMAScript 是通用语法,浏览器给 JS 配的是网页能力,Node.js 给 JS 配的是服务器能力。

Node.js 的本质

Node.js 的本质可以概括为一句话,ECMAScript 加上 Node.js 自己的 API。

浏览器环境给 JS 配的是 DOM、BOM 这些 Web API,Node.js 给 JS 配的是 fs(文件系统)、http(网络服务)、path(路径处理)、os(操作系统信息)这些服务端 API。两者的语言核心相同,外围能力完全不同。

能力 浏览器环境 Node.js 环境
window
document
DOM / BOM
global 全局对象
process 进程信息
fs 文件系统
http 服务能力

在浏览器里写 window 很自然,在 Node.js 里写 window 会直接报 window is not defined,因为 Node.js 环境里根本没有这个对象。后面文章会用 globalprocess 替代它们。

V8 引擎的作用

V8 是 Google 开发的 JavaScript 引擎,负责把 JS 源码编译成机器码再交给 CPU 执行。它的即时编译(JIT)技术让 JS 的执行速度非常快,这也是 Ryan Dahl 当年选中它的原因。

Chrome 浏览器内部用 V8,Node.js 用的也是同一套 V8。所以同样的 JS 代码,在浏览器和 Node.js 里跑,执行性能是同一水平,不需要担心 Node.js 是”缩水版”。

Node.js 的特点

异步非阻塞 I/O

读写文件、发网络请求这类慢操作不会卡住后面的代码。程序先继续往下跑,等结果回来再处理。这点和传统同步模型差别很大,也是新手写 Node.js 时最容易不适应的地方。

console.log("开始");
setTimeout(() => console.log("两秒后执行"), 2000);
console.log("结束");
// 输出顺序是,开始 → 结束 → 两秒后执行

看到没有,setTimeout 没有卡住后面的代码,程序先打印了”结束”,两秒后才回头执行回调。磁盘读写、网络请求都是这个套路,这就是”非阻塞”的含义。

事件驱动

程序的运行围着事件转,文件读完了、请求到达了,都会触发对应的回调函数。写代码时不直接调用,而是注册事件处理函数等它自己触发。

单线程与事件循环

JS 主线程只有一个,靠事件循环排队处理任务,不用像多线程语言那样操心加锁和共享数据。好处是简单,代价是单个计算任务占住线程时,其他任务只能等着。这套模型总结起来一句话,Node.js 擅长等,不擅长算。

Node.js 能做什么

Web 服务器与 API 服务

这是 Node.js 最主流的用途,用内置的 http 模块就能起一个服务器,配合 Express、Koa 等框架可以快速写出 API 接口。它的异步事件模型特别适合聊天、实时推送这类 I/O 密集型的场景。

命令行工具

用 Node.js 可以写命令行程序,读写文件、批量处理数据、自动化脚本都能做。npm 生态里大量 CLI 工具就是 Node.js 写的,比如格式代码的 prettier。

前端构建工具

前端开发常用的 webpack、vite、esbuild 全部运行在 Node.js 上。它们的打包、编译、热更新功能本质上是 Node.js 程序。换句话说,只要做前端开发,电脑里就离不开 Node.js。

和其他后端技术比一比

技术 特点 典型场景
Java 重、类型严格、生态庞大 大型企业级系统
Python 上手快、脚本友好、AI 生态强 数据分析、机器学习、自动化脚本
Go 编译型、部署简单、高并发 云原生、微服务、网关
Node.js 异步 I/O 强、前后端同语言、轻量 Web API、实时应用、工具链

选型没有绝对答案。做 Web API 和开发工具链,Node.js 上手最快,前后端还能共用代码。写底层系统和流量网关,Go 的高并发更稳。企业级业务系统,Java 的生态最成熟。Node.js 不是万能药,CPU 密集型的计算任务它并不擅长,这类场景 Go 和 Java 更合适。但如果你做 Web 开发,希望一套 JS 打通前后端,Node.js 是最顺手的选项。

版本与生态

Node.js 的版本更新很快,官方把版本分成两类,偶数版本号(18.x、20.x)是 LTS 长期支持版,维护周期长、稳定可靠,生产环境都推荐用 LTS。奇数版本是尝鲜版,只维护几个月。本教程所有示例以 Node 20 LTS 为准。

配合 npm registry 上两百多万个开源包,Node.js 的生态基本覆盖了 Web 开发的全部环节,数据库、登录、缓存、消息队列都能找到成熟方案,这也是它流行的重要原因。

实践

这一步先完成安装,安装过程参考 Node.js 环境搭建,按你自己的操作系统选一种方式即可。验证版本用终端操作,Windows 上用 PowerShell 或 CMD,macOS 和 Linux 用自带的终端。装完打开终端输入。

node -v
# 输出类似 v20.18.0,教程基于 Node 20 LTS

npm -v
# 输出类似 10.8.2

能看到版本号说明环境就绪。输入命令后提示找不到 node,一般是安装没成功或者装完没重启终端,回上一篇按排查办法处理。想确认安装位置可以用 where node(Windows)或 which node(macOS 和 Linux),会输出 node 可执行文件的完整路径。环境就绪后就可以开始写代码了。

常见坑

  • 以为 Node.js 是一门新语言。它不是,它只是让 JS 跑在服务器上的运行时环境,语法还是 JS。
  • 以为 Node.js 是个框架。框架是 Express、Koa 这类,Node.js 是底层运行时,自带 httpfs 等基础模块。
  • 装了旧版本还在用。版本太老会缺新语法和新 API,教程里的示例以 Node 20 为准,低于 18 的建议先升级。
  • 在 Node.js 里写 windowdocument。这是浏览器专属对象,Node.js 环境会直接报错,对应的是 globalprocess
  • 把 Node.js 当成多线程语言用。它的主线程只有一个,CPU 密集任务会卡住整个进程,这类任务应该交给别的语言或单独进程。
  • 在 REPL 里测试代码后直接关掉终端,写的变量和代码全部丢失,正式内容要存在 .js 文件里。

装好环境就进入下一关 Node.js 环境搭建,里面还有安装失败的排查办法。

下一篇
Node.js 环境搭建