简介
从浏览器环境到操作系统舞台
在过去,JavaScript 一直被认为是一种仅限于浏览器的语言,主要用于制作网页上的滚动动画和交互效果。然而,随着 Ryan Dahl 的出现,这一切发生了改变。
2009 年,Ryan Dahl 不甘心 JavaScript 只被束缚在浏览器中,他基于当时 Chrome 浏览器的 JavaScript 引擎 V8 创建了 Node.js,赋予了 JavaScript 运行在操作系统层面的能力。
这标志着 JavaScript 迈出了关键的一步,从浏览器环境走向了更广阔的舞台。Node.js 的出现,让 JavaScript 不再局限于网页制作,摇身一变成为了一门功能强大的后端开发语言。
与传统语言的异同
与 Python、Ruby 和 PHP 等传统操作系统语言相比,Node.js 拥有以下几点关键差异:
- 运行环境: 传统语言直接运行在操作系统上,而 Node.js 则通过自己的运行环境来执行 JavaScript 代码;
- 输出方式: 传统语言的程序通常通过图形界面呈现结果,而 Node.js 主要通过命令行界面输出文本信息;
- 核心功能: 传统语言擅长处理系统任务和文件操作,而 Node.js 则专注于网络通信和事件驱动编程;
尽管存在差异,Node.js 的核心仍然是 JavaScript 语言本身。如果你已经掌握了 JavaScript,那么学习 Node.js 将会非常轻松,因为你只需要熟悉一些环境相关的特性和新的 API 即可。
Node.js 的发展之路
自诞生以来,Node.js 经历了快速发展和起伏跌宕。曾经一度陷入停滞,甚至催生了短命的替代方案 IO.js。然而,社区的质疑和竞争反而激发了 Node.js 团队的斗志,他们积极改进,版本更新不断加速,并逐渐赢回了开发者的信任。
如今,Node.js 已成为最流行的后端运行环境之一,被广泛应用于服务器开发、代理服务、构建工具等诸多领域。如果你想涉足 Web 开发,那么掌握 Node.js 必不可少,因为它几乎无所不在,从服务器端到前端框架构建,其身影无处不在。
Node.js 的特点
非阻塞式 I/O 和事件循环
Node.js 以其高效且可扩展的 I/O 模型而闻名,该模型基于非阻塞、事件驱动的架构。
I/O 即输入和输出。「非阻塞式 I/O」意味着 I/O 操作是异步处理的,在运行代码时,可以在单个线程上并发地处理多个任务,不会阻塞主程序的执行。而不像 Ruby、Python 或 PHP 等语言在其标准实现中主要使用传统的阻塞 I/O 模型(程序等待每个 I/O 操作完成后再继续下一个操作),在不使用额外线程等更多计算机资源的情况下无法并发处理多个任务。
Node.js 通过「事件循环」机制来实现这一特性。事件循环就像是一个待办事项注册表,当结合事件循环、回调等一起工作时,它能将需要完成的工作登记在注册表中,按照设定的时间定时器完成工作后,注册表会调用代码中的一个函数来告知工作已完成,从而实现任务的并行处理。
需要注意的是,浏览器和 Node.js 的事件循环实现方式显然不同,因为一个是在计算机系统层面的事件循环及相关资源管理,一个是在浏览器环境中的事件循环及资源调用,但从使用者角度来看原理相似。
优势和劣势
在处理并发任务方面,Node.js 具有天然的优势,这得益于其非阻塞式 I/O 特性。例如在服务器处理并发请求方面,Node.js 表现出色,在默认情况下无需任何优化就能比其他框架处理更多的并发请求每秒。
但由于 Node.js 默认只使用一个线程,所以在处理 CPU 密集型任务(如 AI 或机器学习)时表现不佳,人们通常会选择 Python 来处理这类任务。
安装 Node.js
安装 Node.js 的最直接方法是前往 Node.js 的官方网站下载对应你所用系统的安装包,但个人更推荐使用版本管理器。
为什么需要版本管理器?在进行多个项目开发时,有时候会面临不同项目需要不同 Node.js 版本的情况,借助版本管理器可以避免来回安装卸载的麻烦。
Node.js 的版本管理器也有很多,这里介绍 Volta 和 nvm
Volta
Volta 是用 Rust 构建的快速、跨平台、无障碍的 JavaScript 工具管理器
你在可以在 macOS、Linux、Windows 上的 WSL2 上使用以下命令安装:
# 安装 Volta
curl https://get.volta.sh | bash
# 安装 Node.js LTS 版
volta install node
# 安装指定版本的 Node.js
volta install node@22
# 查看已经安装的版本
volta list node
# 卸载指定版本
volta uninstall node@22
更多实用方法可以查看 Volta 的官方指南
nvm
nvm(Node Version Manager)更经典更为人熟知,它是一个符合 POSIX 标准的 bash 脚本,用于管理多个活动的 Node.js 版本。
你在可以在 macOS、Linux、Windows 上的 WSL2 上使用以下命令安装:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/master/install.sh | bash
安装完成后针对你所使用的 shell 编辑其配置文件,如我使用的 shell 为 zsh,那么:
vim ~/.zshrc
除了 zsh,其他的一些常见 shell 的路径及文件名通常为:
- bash:
~/.bashrc
- zsh:
~/.zshrc
- ksh:
~/.profile
如果你不知道自己所使用的 shell 可以使用命令 echo $SHELL
,通过其返回结果如 /bin/bash
你就知道这是使用的 bash,一般来说大多数 Linux 和旧版本的 macOS 都是使用的 bash
在配置文件底部添加如下内容:
export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
然后使用命令另其生效:
# 如果你使用的是其他 shell 则如下示例的 ~/.zshrc 也要相应修改
source ~/.zshrc
查看 nvm 版本:
nvm -v
0.38.0
能看到版本号表示安装及配置成功了,然后使用 nvm 安装 Node.js:
# 列出可安装的 Node.js 版本
nvm ls-remote
# 安装
nvm install --lts # 安装 LTS 版 Node.js
nvm install node # 安装最新版 Node.js
nvm install 20.10.0 # 安装指定版本 Node.js
# 使用指定版本
nvm use node # 使用安装好的最新版
nvm use --lts # 使用安装好的 LTS 版
# 查看安装路径
nvm which 20.0.0
# 卸载
nvm uninstall 20.0.0 # 卸载指定版本
运行
在安装完成后,可以在终端运行命令 node
,这样就进入了 Node.js 的交互式解释器,即 REPL(Read Eval Print Loop)。如果使用过 Python 等其他语言应该会感到熟悉,不然也可能觉得它像浏览器里的 Console
可以动手试试它都可以执行哪些内容,哪些是浏览器能执行但是在 Node.js 中不能执行的
但一般来说并不会直接使用 Node.js REPL
如果不知道在终端中从 REPL 中退出来,可以输入
.exit
或按Ctrl
+D
编写一个最简单的 JavaScript 代码:
console.log('hi')
并存成 index.js
文件,然后使用命令:
node index.js
这就是一个简单的如何在浏览器以外的环境通过 Node.js 运行一段代码的方法了
浏览器 vs Node.js
全局对象
- 浏览器中,几乎所有东西都附加在
window
对象上,因此你可以直接使用alert
函数; - 在 Node.js 中没有
window
对象。Node.js 中有一个名为global
的对象,相当于 Node.js 中的window
对象,但很少使用;
// 在浏览器中
console.log(window);
// 在 Node.js 中
console.log(global);
通过条件判断(如检查 window
是否存在)可以编写兼容两环境的 JavaScript 代码。
许多熟悉的函数(例如 clearTimeout
或 setTimeout
)在两者中都存在,但使用方式可能有所不同;
操作 DOM
- 浏览器拥有 DOM (Document Object Model),用于操作网页元素;
- Node.js 没有任何 DOM,因为它运行在服务器端,不负责渲染网页;
模块 浏览器和 Node.js 都支持模块,但定义方式不同:
- 浏览器使用
<script type="module">
标签导入模块 可以使用脚本标签在浏览器中导入模块,将type
属性设置为module
并将src
属性设置为模块文件的路径:<script type="module" src="./module.js"></script>
可以从名为 module.js 的模块导入
sayHello
函数,并在主 JavaScript 文件中使用它:import { sayHello } from './module.js'; sayHello();
- Node.js 则使用
import
和export
语句。import { module } from './module.js';
Node.js REPL(Read-Eval-Print-Loop)
- 浏览器和 Node.js 都提供 REPL 环境,用于直接执行 JavaScript 代码;
- Node.js 的 REPL 适合快速测试代码片段,但不适合构建应用程序;
服务器与网站 Node.js 主要用于服务器端应用程序,而浏览器则用于网站
最后,如果感兴趣,可以看看「Node.js:纪录片 | 一个起源故事」
浏览「JavaScript 和它的朋友们专题」可查看更多内容