node.js
2024/10/7大约 8 分钟
node.js
node.js是一个基于Chrome引擎的JavaScript运行环境,用于在本地运行JavaScript代码
1. 安装
1.1 安装node管理工具nvm
Linux安装
请查看官方下载页面,已提供对应的命令行安装方法,包含docker、nvm等方式
- 由于
node更新速度快,使用与开发不同版本的node可能导致项目有不兼容问题,因此,node版本可能需要频繁切换,但官方的更新工具很难成功完成一次更新,因此需要使用nvm,一个社区版的允许快速切换node版本和快速安装node的工具nvm通过软链接将当前使用的node链接到配置了环境变量的node文件夹
- 从nvm项目地址找到安装包或安装脚本,执行安装
- 如果之前安装了
node,需要先删除node再安装,windows可以在控制面板卸载,卸载完成要保证命令行无法找到npm
- 如果之前安装了
- 安装
node并使用安装好的node:
# 在安装目录下找到setting.txt文件,编辑内容切换安装node的镜像源
# 阿里云(淘宝)
node_mirror: https://npmmirror.com/mirrors/node/
npm_mirror: https://npmmirror.com/mirrors/npm/
# 腾讯云
node_mirror: http://mirrors.cloud.tencent.com/npm/
npm_mirror: http://mirrors.cloud.tencent.com/nodejs-release/
# 安装最新版node
nvm install node
# 安装特定版本node,比如:18.17.1
nvm install 18.17.1
# 列出已下载的所有node版本
nvm ls
# 列出所有可安装版本
nvm ls available
# 使用特定版本
nvm use 18.17.1
# 删除特定版本node
nvm uninstall 18.17.1关于node版本更新
如果希望更新nodejs版本,最简单的方法是使用nvm安装一个新的nodejs,然后切换到最新版本 由于切换完成后全局包需要重新安装,可以在原nodejs环境获取所有全局包然后在新环境重新下载
# 获取全局包列表
npm list -g --depth=0 --json > global-modules.json对global-modules.json的处理
获取到的json如下:
{
"resolved": "file:nvm/v22.9.0",
"dependencies": {
"corepack": {
"version": "0.29.3",
"overridden": false
},
"npm": {
"version": "10.8.3",
"overridden": false
},
"nrm": {
"version": "1.3.0",
"overridden": false
},
"pnpm": {
"version": "9.12.0",
"overridden": false
},
"yarn": {
"version": "1.22.22",
"overridden": false
}
}
}可以通过node脚本读取json文件并执行安装操作
const fs = require('fs');
// 读取 JSON 文件
const data = JSON.parse(fs.readFileSync('global-modules.json', 'utf8'));
// 提取模块名
const modules = Object.keys(data.dependencies).map(dep => `${dep}@${data.dependencies[dep].version}`);
// 安装模块
const { execSync } = require('child_process');
execSync(`npm install -g ${modules.join(' ')}`, { stdio: 'inherit' });1.2 配置node
- 切换
npm镜像
# 设置为淘宝镜像
npm config set registry https://registry.npmmirror.com- 安装npm镜像管理工具nrm(可选)
npm install -g nrm
# 查看可选源
nrm ls
# 使用对应源仓库
nrm use <registry>
# 添加自定义源仓库
nrm add <registry> <url>
# 删除对应源仓库
nrm del <registry>
# 测试速度
nrm test <registry>
# 查看当前使用源和url
nrm current- 新建下载目录存放npm下载文件:通过npm安装会将下载文件存放到
C:\Users\用户名\AppData\Local\npm-cache,全局包存放在nodejs根目录下 - 为了管理方便,并空出
c盘空间,在nodejs目录下创建两个文件夹node_global和node_cache
# 修改使用新建目录下载文件
npm config set prefix "D:\nodejs\node_global"
npm config set cache "D:\nodejs\node_cache"添加
node_global文件夹环境变量,对于全局包而言,一般都是需要命令行使用的脚本- 将文件夹
D:\nodejs\node_global\node_modules添加到环境变量中
之前和node在同一文件夹下,而nrm安装时已经添加了环境变量,如果不修改目录不需要额外添加环境变量
- 将文件夹
npm常见命令:
# 初始化项目
npm init
# 安装所有依赖
npm install
# 添加依赖,可以简写成 i
npm install ...
# 卸载依赖
npm uninstall ...
# 更新依赖
npm update ...
# 运行package中的命令
npm run ...
# 当前项目已安装依赖
npm list- 快速删除
node_modules文件夹
# 安装rimraf
npm install rimraf -g
# 删除node_modules
rimraf node_modules- 自动重启node运行的文件:node支持直接运行js文件,但并不能在文件改变后自动重启,如果有此需求可以安装
nodemon
npm install nodemon -g
# 相当于使用 node test 运行 test.js
nodemon test1.3 安装其他node包管理工具
- 由于npm安装存在速度慢,安装空间占用大的问题,社区中出现了一些新的包管理工具
1.3.1 yarn
Yarn是facebook发布的一款取代npm的包管理工具,主要是改进了安装速度、正确性,并添加了工作区等新功能,相关命令文档见yarn中文网- 安装与更新:
npm install -g yarn
# 更新,npm中的yarn定格在了1.X版本,因此下载后需要手动更新
yarn set version stable
yarn install- 配置
yarn:
# 设置缓存目录
yarn config set cache-folder "D:\nodejs\.yarn-cache"
# 设置镜像,当然也可以使用yrm进行管理 yarn global add yrm
yarn config set registry "https://registry.npmmirror.com"- 常用命令基本与
npm相同:
# 全局安装包
yarn global add ...
# 创建项目
yarn init
# 为项目添加依赖,-D添加为生产依赖
yarn add ...
# 移除依赖
yarn remove ...
# 升级所有依赖
yarn upgrade
# 升级某个依赖
yarn upgrade ...
# 运行package中的脚本,相对于npm run ...
yarn ...
# 当前项目已安装的依赖
yarn list- yarn项目需要添加到.gitignore的文件
.yarn/*
!.yarn/cache
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions1.3.2 pnpm
- pnpm是速度快、节省磁盘空间的软件包管理器
- 同yarn和npm一样,pnpm仍然使用缓存来保存已经安装过的包,以及使用pnpm-lock.yaml来记录详细的依赖版本
- 不同于yarn和npm, pnpm使用符号链接和硬链接的做法来放置依赖,从而规避了从缓存中拷贝文件的时间,使得安装和卸载的速度更快
- 由于使用了符号链接和硬链接,它选择使用树形的依赖结果,有着几乎完美的依赖管理。也因为硬链接的局限导致pnpm的存储目录不能够链接到其他盘,可能导致其他盘存在备份
pnpm目前只支持扁平的项目依赖结构,即无法使用来自依赖的依赖,只能使用项目的
package.json中指定的依赖 - 安装
npm install pnpm -g- 配置
# 设置镜像
pnpm config set registry "https://registry.npmmirror.com"
# 修改下载目录
pnpm config set store-dir "D:\nodejs\.pnpm-store"
# 对项目级别设置目录,修改pnpm-store.yaml,添加以下内容
# storeDir: "/path/to/project-store"- 常见命令
# 查看某依赖的所有版本
pnpm view ... version
# 全局安装包
pnpm add ... -g
# 创建项目
pnpm init
# 安装所有依赖
pnpm install
# 添加依赖
pnpm add ...
# 删除依赖
pnpm remove ...
# 更新依赖
pnpm upgrade ...
# 更新所有依赖
pnpm up
# 当前项目已安装依赖
pnpm list基础
事件循环机制
- 在
Node.js中,事件循环由libuv库负责构建,在Node.js执行过程中v8引擎解析脚本,调用Node APIlibuv库负责Node API的执行,它将不同的任务分配给不同的线程,形成一个事件循环,之后以异步的方式将结果返回给v8引擎v8引擎将结果返回给用户
Node.js中相比浏览器提供了更多的宏任务执行阶段,每个宏任务在特定的阶段执行,虽然实际执行阶段有很多,但我们关注的阶段按顺序展示如下:timers:定时器任务,包括setTimeout、setInterval的回调pending callbacks:执行延迟到下一轮的I/O回调。此阶段用于执行一些系统操作的回调,例如TCP错误类型idle, prepare:Node.js内部使用,不做用户代码调用poll:检索新的I/O事件,计算它应该阻塞和轮询I/O多长时间;执行与I/O相关的回调v8将脚本解析后进入libuv时,处于此阶段- 如果此阶段任务队列已经执行完,有
setImmediate任务,则进入check阶段,如果没有就等待新任务 - 如果轮询队列为空且有定时任务到期,将回到
timers阶段
check:setImmediate()回调在此处调用close callbacks:一些close回调,比如socket.destroy()
Node.js中还额外提供了两个新的和任务队列有关的方法,效果是在任务队列中添加任务,其中Tick属于微任务,但在所有微任务最前面优先执行process.nextTick():在每阶段执行完毕后立即调用,属于微任务,一次执行完,官方给的样例用途是确保服务的listen事件触发在用户定义完事件监听回调之后setImmediate():作为宏任务,可能需要多轮执行才能执行完
工作池
libuv中提供了昂贵任务的处理线程,包括操作系统不提供的非阻塞I/O和特别占用CPU的任务,这些线程都由在工作者池worker pool(也称为线程池)中的线程执行,这是不同于事件循环线程的线程类型- 常见的模块包括
I/O密集型DNS- 除了
fs.FSWatcher()外的所有文件系统api
CPU密集型cryptozlib(除了显式同步以外的所有api)
worker完成时将为事件循环引发"至少一个任务完成"事件
