Node.js 概述

Node.js 是一个开源和跨平台的 JavaScript 运行时环境。在浏览器之外运行 V8 引擎(它解析和执行 JavaScript 代码,每个浏览器都有自己的一个引擎,而 V8 就是 Goole 浏览器的引擎)。Node.js 在单个进程中运行(注意 Node.js 不是单线程,这里的单个进程指的是 js 引擎所在的主线程(负责执行同步代码、处理回调函数)),不会为每个请求创建新线程。Node.js 在其标准库中提供了一组异步 I/O 原语,可防止 JavaScript 代码阻塞。

异步 Node.js 的实现原理

node.js 底层依赖 libuv 库,libuv 内部维护了一个事件循环线程(js 的主线程),一个线程池,默认有 4 个线程,用于处理耗时的 I/O 操作,如文件读写、DNS 解析,还有其它专门处理特定功能的线程,如网络请求的线程等。


当 js 执行 promise 时,会将异步任务交给与其相对应的功能线程中执行,当执行完成后,会将对应的回调函数,放入任务队列,等待主线程处理。


JavaScript 主线程在同步代码执行完毕后,会进入事件循环,不断从任务队列中取出回调函数执行。


JavaScript 主线程是单线程的,但 Node.js 进程通过 libuv 管理了多个线程,这些线程负责 “跑腿” 处理异步操作,主线程只负责 “调度”。

当 Node.js 执行 I/O 操作时,Node.js 不会阻塞线程并浪费 CPU 周期等待,而是会在响应返回时恢复操作。这使 Node.js 能够使用单个服务器处理数千个并发连接,而 ​​ 不会带来管理线程并发的负担

WebAssembly

WebAssembly 是一种高性能的汇编类语言,可以从各种语言编译,包括 C/C++、Rust 和 AssemblyScript。WebAssembly 规范详细说明了两种文件格式,一种二进制格式称为 WebAssembly 模块,带有 .wasm 扩展名,相应的文本表示称为 WebAssembly 文本格式,带有 .wat 扩展名。

  • 模块:已经编译的 WebAssembly 二进制文件,即.wasm
  • 内存: 一个可调整大小的 ArrayBuffer
  • 表:可调整大小的类型化引用数组未存储在内存中
  • 实例:模块及其内存、表和变量的实例化
    可将我们的 js 代码编译为.wasm 格式,之后可以通过 WebAssembly 对象来处理我们的二进制文件
    示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
// Assume add.wasm file exists that contains a single function adding 2 provided arguments
const fs = require("node:fs");

// Use the readFileSync function to read the contents of the "add.wasm" file
const wasmBuffer = fs.readFileSync("/path/to/add.wasm");

// Use the WebAssembly.instantiate method to instantiate the WebAssembly module
WebAssembly.instantiate(wasmBuffer).then((wasmModule) => {
// Exported function lives under instance.exports object
const { add } = wasmModule.instance.exports;
const sum = add(5, 6);
console.log(sum); // Outputs: 11
});

当使用 —inspect 开关启动时,Node.js 进程会监听调试客户端。默认情况下,它将在主机和端口 127.0.0.1:9229 上监听。每个进程还分配有一个唯一的 UUID。

1
node --inspect server.js

我们可以通过 fetch 来获取其它服务器的请求
node.js 可以读取文件、使用 websocket 和 http 与其他服务器进行通讯,可以做后端也可以做前端,代码都是通过 js 或者 ts 来编写,支持异步编程。如果想具体了解这些信息可以自行学习,因为我平时只用 node.js 来管理包。

npm 包管理工具

npm 是 Node.js 的标准包管理器,类似的包管理器还有 yarm、pnpm
包是 npm 安装、更新和管理项目依赖的下载。依赖是预先构建的代码片段,例如库和包,你的 Node.js 应用需要它们才能运行。
npm 包含两部分:

  • 命令行工具(CLI):通过终端操作依赖管理
  • npm registry(包仓库):一个远程数据库,存储了超过 200 万个开源包,开发者可直接下载使用。

核心概念

  • 包:包括核心代码文件,核心代码文件
  • 依赖:项目运行或开发过程中需要的外部包
  • package.json:记录项目基本信息和依赖配置,位于项目根目录。必须手动创建或通过 npm init 生成。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
"name": "my-project", // 项目名称(发布包时需唯一)
"version": "1.0.0", // 版本号(遵循语义化版本)
"description": "我的第一个项目",
"main": "index.js", // 入口文件(其他包引用时的默认文件)
"dependencies": {
// 生产依赖
"lodash": "^4.17.0"
},
"devDependencies": {
// 开发依赖
"jest": "^29.0.0"
},
"scripts": {
// 自定义脚本(通过`npm run <脚本名>`执行)
"start": "node index.js",
"test": "jest"
},
"author": "你的名字",
"license": "MIT" // 开源许可证
}
  • node_modules:安装的依赖包会被存放在项目根目录的 node_modules 文件夹中
  • package-lock.jsonnpm :5+ 引入的文件,锁定依赖版本。

常用命令

  • 初始化项目:npm init -y
  • 安装所有依赖:npm install
    • 安装单个包:npm install <包名>
    • 安装开发依赖:npm install <包名> —save-dev
    • 安装指定版本:npm install <包名>@<版本号>
    • 全局安装:npm install <包名> -g
  • 更新软件包:npm update
  • 卸载依赖;npm uninstall
  • 运行任务:npm run
  • 查看项目依赖树:npm list
  • 将自己的包发布到 npm registry:npm publish

配置.npmrc 文件

切换镜像源:

1
registry=https://registry.npmmirror.com/  # 淘宝镜像

和其他包管理器对比

npm:node.js 默认的包管理器,兼容性好,速度慢
yarn:facebook 开发,早期解决 npm 速度问题,缓存机制强,安装速度快,支持离线安装
pnpm:采用硬链接,节省磁盘空间,依赖安装最快,严格的依赖隔离

NVM

nvm 是一个专门用于管理 Node.js 版本的命令行工具
功能

  • 支持同时安装多个不同版本的 Node.js,通过命令在已安装的版本间切换,解决不同项目对 Node.js 版本兼容性的要求。
  • 允许为单个项目指定专属的 Node.js 版本,通过在项目根目录创建.nvmrc 文件,运行 nvm use 即可自动切换到该项目所需版本
  • 快速卸载不需要的 Node.js 版本

安装

git 安装

  1. 在 git bash 中执行cd ~/.nvm
  2. 执行git checkout 版本
  3. . ./nvm.sh
  4. 将以下代码添加到~/.bashrc、~/.profile 或 ~/.zshrc 文件中
1
2
3
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion

使用

基本用法

  • 安装最新版的 node:nvm install node
  • 安装特定版本的 node:nvm install 14.7.0
  • 给特定版本的 node 设置别名:nvm alias my_alias v14.4.0
  • 查看可用版本:nvm ls-remote
  • 查看已安装的版本:nvm ls
  • 使用特点版本:nvm use node||nvm run node --version
  • 获取安装路径:nvm which 12.22
  • 设置默认 node 版本:nvm alias(别名) default 18.12(版本)
  • 卸载:
1
2
3
nvm_dir="${NVM_DIR:-~/.nvm}"
nvm unload
rm -rf "$nvm_dir"

长期支持:

Node 的长期支持 (LTS) 版本号为 schedule。你可以在别名和 .nvmrc 文件中引用 LTS 版本

  • lts/* 表示最新的 LTS
  • 安装最新长期支持的版本:nvm install --lts

安装过程迁移全局包

+安装新版本的 Node.js 并从旧版本迁移 npm 包:nvm install --reinstall-packages-from=node node

  • 从特定版本的 Node 安装和迁移 npm 包:
    1
    2
    nvm install --reinstall-packages-from=5 6
    nvm install --reinstall-packages-from=iojs v4.2
  • 获取当前 node 版本支持的最新 npm 版本:nvm install-latest-npm
  • 安装时从文件中获取默认全局包:将软件包名称添加到$NVM_DIR/default-packages文件中
1
2
3
4
5
# $NVM_DIR/default-packages

rimraf
object-inspect@1.0.2
stevemao/left-pad

.nvmrc

你可以在项目根目录(或任何父目录)中创建一个包含 Node 版本号的.nvmrc 文件。之后,如果命令行中未提供版本,nvm use、nvm install、nvm exec、nvm run 和 nvm which 将使用 .nvmrc 文件中指定的版本。
示例:

1
2
3
4
5
echo "5.9" > .nvmrc

echo "lts/*" > .nvmrc # to default to the latest LTS version

echo "node" > .nvmrc # to default to the latest version