nodejs
Node.js — 在任何地方运行 JavaScript
版本控制
一、Node. js 运行时版本管理
1. 使用版本管理工具
| 工具名 |
特点 |
命令示例 |
| nvm |
最流行的 Node 版本管理工具(仅限 macOS/Linux) |
nvm install 20
nvm use 18 |
| fnm |
更快的替代工具,跨平台支持(Rust 编写) |
fnm install 20
fnm use 18 |
| Volta |
跨平台工具,支持自动版本切换(由 Rust 编写) |
volta install node@20 |
| n |
轻量级工具(但需全局安装 Node. js 作为依赖) |
n 20 |
| nvm-windows |
Windows 专用版 nvm |
nvm install 20 |
2. 推荐工具:nvm
1 2 3 4 5 6 7
| curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
nvm install 20 nvm use 20 nvm alias default 20 nvm ls
|
3. 自动版本切换
在项目中添加 .nvmrc 文件指定版本:
1 2 3 4
| echo "20" > .nvmrc
nvm use
|
4.fnm vs nvm 对比
| 特性 |
fnm |
nvm |
| 速度 |
⚡️ 极快(Rust 编写) |
较慢(Shell 脚本) |
| 跨平台支持 |
Windows/macOS/Linux |
Windows/macOS/Linux |
| 自动版本切换 |
内置支持(--use-on-cd) |
需插件扩展 |
| 依赖管理 |
无全局 Node 依赖 |
需要预装 Node |
fnm
1 2 3 4 5 6 7 8 9 10
| # 安装 fnm (快速 Node 管理器) winget install Schniz.fnm # 配置 fnm 环境 fnm env --use-on-cd | Out-String | Invoke-Expression # 下载并安装 Node.js fnm use --install-if-missing 22 # 验证环境中是否存在正确的 Node.js 版本 node -v # 应该打印 `v22.12.0` # 验证环境中是否存在正确的 npm 版本 npm -v # 应该打印 `10.9.0`
|
配置 fnm 环境
为了在切换目录时自动加载对应的 Node.js 版本,需要在 %USERPROFILE%Documents/WindowsPowerShell 目录下 Microsoft.PowerShell_profile.ps1 文件中添加 fnm env --use-on-cd | Out-String | Invoke-Expression,若没有对应文件夹或文件手动创建即可。
!fnm.png
node 原理
Node.js 是一个开源的、跨平台的 JavaScript 运行时环境,它允许开发者在服务器端运行 JavaScript 代码。以下是 Node.js 的一些核心原理:
一、基于 V8 引擎
- V8 引擎简介
- V8 是由 Google 开发的高性能 JavaScript 引擎,最初是为 Chrome 浏览器设计的。它能够将 JavaScript 代码编译成机器码,从而实现快速执行。Node.js 利用 V8 引擎,使得 JavaScript 代码在服务器端也能像在浏览器端一样高效运行。
- V8 引擎采用即时编译(JIT)技术。当 JavaScript 代码执行时,V8 会动态地将 JavaScript 代码转换为本地机器码。例如,对于一个简单的数学运算函数,V8 引擎会分析这个函数的执行路径,将其中的运算逻辑编译成高效的机器指令,这样在后续调用该函数时就能快速执行,大大提高了 JavaScript 代码的执行速度。
- 与 Node.js 的结合
- Node.js 将 V8 引擎嵌入到自己的架构中。它为 V8 提供了运行环境,包括内存管理、垃圾回收等功能。同时,Node.js 还扩展了 V8 的功能,使其能够访问操作系统层面的资源,如文件系统、网络等。例如,Node.js 通过自己的模块系统,让 JavaScript 代码可以调用内置的文件系统模块(fs 模块),利用 V8 引擎执行相关的文件操作函数,实现对服务器本地文件的读写。
二、事件驱动和非阻塞 I/O 模型
- 事件驱动机制
- Node.js 采用事件驱动架构。在 Node.js 应用程序中,存在一个事件循环(Event Loop)。当一个异步操作(如文件读取、网络请求等)被发起时,它会被放入事件队列中。一旦这个异步操作完成,就会触发一个事件,事件循环会检测到这个事件,并调用与之关联的回调函数来处理结果。
- 例如,当使用 Node.js 的 http 模块创建一个 HTTP 服务器时,服务器监听端口的操作是异步的。当有客户端请求到达服务器端口时,会触发一个“request”事件。事件循环会调用预先注册的处理请求的回调函数,这个回调函数可以获取请求信息并进行相应的响应处理。这种事件驱动的方式使得 Node.js 能够高效地处理大量的并发请求,因为它不需要为每个请求创建新的线程或进程,而是通过事件循环来统一管理和调度。
- 非阻塞 I/O
- 在传统的服务器端编程中,I/O 操作(输入/输出操作,如读取文件、数据库查询等)往往是阻塞的。这意味着当一个 I/O 操作在执行时,程序会暂停执行后续的代码,直到 I/O 操作完成。而 Node.js 采用非阻塞 I/O 模型,当发起一个 I/O 操作时,程序不会等待 I/O 操作完成,而是继续执行后面的代码。
- 例如,在使用 Node.js 的 fs 模块异步读取文件时,调用 fs.readFile() 方法后,程序不会停留在读文件这一步。它会继续执行后续的代码,如设置其他事件的回调函数等。当文件读取完成时,通过事件驱动机制触发回调函数来处理读取到的数据。这种非阻塞 I/O 模型使得 Node.js 在处理 I/O 密集型任务时非常高效,能够充分利用单个 CPU 核心,避免了多线程编程中可能出现的线程上下文切换等问题。
三、单线程与多线程协作
- 单线程执行 JavaScript 代码
- Node.js 的 JavaScript 代码是在单个线程中执行的。这个线程就是运行 V8 引擎的线程。所有的 JavaScript 函数调用、逻辑判断等操作都是在这个单线程中顺序执行的。这种单线程模型简化了编程模型,开发者不需要考虑复杂的线程同步、锁等问题。
- 例如,在一个 Node.js 脚本中,有多个函数调用和变量赋值操作。这些操作都是按照代码的顺序,在单个线程中依次执行。这使得代码的执行顺序非常明确,便于理解和调试。
- 多线程协作处理底层任务
- 尽管 JavaScript 代码是在单线程中执行,但 Node.js 在底层会利用多线程来处理一些任务。对于一些耗时的 I/O 操作,如文件系统操作、网络通信等,Node.js 会将这些操作委托给操作系统提供的线程池来执行。
- 例如,在进行文件写入操作时,Node.js 会将写文件的任务提交给底层的线程池中的一个线程。这个线程专门负责与操作系统的文件系统接口进行交互,完成文件写入工作。一旦写入完成,会通过事件驱动机制通知单线程的 JavaScript 代码,触发相应的回调函数。这样,Node.js 既利用了单线程的简单性来执行 JavaScript 代码,又通过多线程协作来提高 I/O 操作的效率。
四、模块化系统
- CommonJS 模块规范
- Node.js 采用 CommonJS 模块规范来组织代码。每个 JavaScript 文件都可以作为一个模块。模块之间通过 require() 函数来相互引用。例如,有一个 user.js 模块,它定义了用户相关的函数和变量。在另一个文件 app.js 中,可以通过 require(‘./user’) 来引入 user.js 模块,从而在 app.js 中使用 user.js 中定义的函数和变量。
- 每个模块都有自己的作用域,模块内部定义的变量和函数默认不会暴露到全局作用域。只有通过 module.exports 或 exports 对象导出的内容,才能被其他模块引用。这种模块化方式使得代码的组织更加清晰,便于维护和复用。
- 内置模块和第三方模块
- Node.js 提供了许多内置模块,如 fs(文件系统模块)、http(HTTP 服务器模块)、path(路径处理模块)等。这些内置模块为开发者提供了丰富的功能,用于处理常见的服务器端任务。同时,Node.js 社区也非常活跃,有大量的第三方模块可供使用。开发者可以通过 npm(Node Package Manager)这个包管理工具来安装和管理第三方模块。例如,express 是一个非常流行的第三方模块,它是一个基于 Node.js 的 web 开发框架,通过 npm install express 命令就可以安装到项目中,为开发 web 应用提供更便捷的路由处理、中间件支持等功能。
与 js 的区别
Node.js 和浏览器端的 JavaScript 有一些显著的区别,主要体现在运行环境、API、用途等方面,以下是详细对比:
一、运行环境
- 浏览器端 JavaScript
- 浏览器端的 JavaScript 运行在浏览器环境中。它与 HTML 和 CSS 紧密结合,主要用来操作浏览器的 DOM(文档对象模型)和 BOM(浏览器对象模型)。例如,通过 JavaScript 可以获取页面中的元素,修改元素的样式、内容等。当用户在浏览器中打开一个网页时,网页中的 JavaScript 代码会在浏览器的 JavaScript 引擎(如 Chrome 的 V8、Firefox 的 SpiderMonkey 等)中执行。
- 浏览器端 JavaScript 的执行受到浏览器安全策略的限制。例如,它不能直接访问本地文件系统,以防止恶意脚本窃取用户本地文件。它只能在浏览器提供的沙箱环境中运行,与服务器端的交互通常通过 AJAX(异步 JavaScript 和 XML)等技术实现。
- Node.js
- Node.js 是一个在服务器端运行 JavaScript 的环境。它基于 Chrome 的 V8 引擎构建,但运行在服务器的操作系统上,如 Linux、Windows 等。Node.js 可以直接访问服务器的文件系统、网络接口等资源。例如,使用 Node.js 的 fs 模块可以读写服务器本地的文件,创建、删除文件夹等。
- Node.js 没有浏览器端的那些安全限制,因为它主要运行在服务器端,由服务器管理员控制。它可以执行各种系统级的操作,如启动网络服务、执行系统命令等,这使得 Node.js 能够在服务器端构建各种应用程序,如 web 服务器、网络服务端程序等。
二、API
- 浏览器端 JavaScript API
- 浏览器端 JavaScript 提供了大量的 API 来操作网页和浏览器功能。例如,DOM API 可以用来创建、修改和删除 HTML 元素。通过 document.getElementById() 可以获取页面中的元素,通过 element.innerHTML 可以修改元素的内部 HTML 内容。
- BOM API 提供了对浏览器窗口、历史记录等的控制。例如,window.location 可以获取或设置当前页面的 URL,history.back() 可以实现浏览器的后退功能。还有诸如事件 API,可以用来监听和处理各种用户交互事件,如点击事件(click)、鼠标移动事件(mousemove)等。
- Node.js API
- Node.js 提供了一系列用于服务器端开发的 API。例如,fs 模块提供了文件系统操作的 API,像 fs.readFile() 可以异步读取文件内容,fs.writeFile() 可以写入文件。path 模块提供了路径处理的 API,如 path.join() 可以用来连接路径,path.basename() 可以获取路径的文件名部分。
- http 模块是 Node.js 中非常重要的一个模块,它提供了创建 HTTP 服务器和客户端的功能。通过 http.createServer() 可以创建一个 HTTP 服务器,用来监听端口并处理客户端的请求。此外,还有像 os 模块(提供操作系统相关的信息)、crypto 模块(提供加密功能)等,这些 API 都是针对服务器端开发场景设计的。
三、用途
- 浏览器端 JavaScript
- 浏览器端 JavaScript 主要用于增强用户体验和实现页面的动态交互。例如,在一个电商网站中,当用户点击“加入购物车”按钮时,通过 JavaScript 可以在不刷新页面的情况下,将商品信息添加到购物车列表中,并更新购物车的数量显示。它还可以用来实现表单验证,在用户提交表单之前,检查输入的数据是否符合要求,如检查邮箱地址格式是否正确、密码是否符合强度要求等。
- 它也可以用于创建单页面应用程序(SPA)。在 SPA 中,页面的内容会根据用户的操作动态加载和更新,而不是像传统的多页面应用程序那样频繁地刷新页面。例如,一些现代的前端框架(如 Vue.js、React.js)结合浏览器端 JavaScript,可以构建出非常流畅和响应式的用户界面。
- Node.js
- Node.js 主要用于服务器端开发。它可以用来构建高性能的 web 服务器。例如,使用 Express.js 这个基于 Node.js 的框架,可以快速搭建一个 web 应用程序,处理用户的 HTTP 请求,返回动态生成的 HTML 页面、JSON 数据等。Node.js 也可以用于构建实时通信应用,如聊天服务器。通过 WebSocket 协议,Node.js 能够实现服务器与客户端之间的双向实时通信,当一个用户发送消息时,服务器可以立即将消息推送给其他在线用户。
- 除了 web 开发,Node.js 还可以用于构建命令行工具。开发者可以利用 Node.js 的文件系统和进程控制等 API,创建一些用于代码格式化、自动化构建等任务的命令行工具。此外,Node.js 也可以用于物联网(IoT)领域,作为设备端的服务器,处理设备之间的通信和数据传输。
四、性能特点
- 浏览器端 JavaScript
- 浏览器端 JavaScript 的性能主要体现在页面的响应速度和交互的流畅性上。现代浏览器的 JavaScript 引擎已经非常高效,能够快速执行 JavaScript 代码。但是,由于浏览器端 JavaScript 需要操作 DOM,而 DOM 操作相对是比较耗时的,如果在执行 JavaScript 代码过程中频繁地进行大量的 DOM 操作,可能会导致页面出现卡顿现象。例如,在一个列表中动态添加大量元素时,如果没有采用合适的优化方法,如使用文档片段(DocumentFragment)等,可能会使页面渲染变慢。
- Node.js
- Node.js 的性能优势在于其事件驱动和非阻塞 I/O 模型。这种模型使得 Node.js 在处理大量并发 I/O 操作时表现出色。例如,在一个高并发的 web 服务器场景中,当有成千上万个客户端同时发起请求时,Node.js 能够通过事件循环和非阻塞 I/O 机制,高效地处理这些请求,而不需要为每个请求创建新的线程或进程。这大大减少了系统资源的消耗,提高了服务器的吞吐量。然而,Node.js 在处理 CPU 密集型任务时可能会相对较弱,因为它的 JavaScript 代码是在单个线程中执行的。如果一个 CPU 密集型的操作(如复杂的数学计算)耗时过长,会阻塞事件循环,影响其他任务的处理。不过,可以通过一些方法,如将 CPU 密集型任务放到子进程中处理等,来解决这个问题。
知识点
Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时环境,用于构建高性能的服务器端应用程序。以下是 Node.js 的一些核心知识点,涵盖其基础、核心模块、异步编程、事件驱动机制、生态系统等方面。
1. Node.js 基础
- 什么是 Node.js?
- Node.js 是一个开源的、跨平台的 JavaScript 运行时环境,允许开发者在服务器端运行 JavaScript。
- 它基于 Chrome 的 V8 引擎,专为高性能和高并发设计。
- 安装 Node.js
- Node.js 的特点
- 单线程:Node.js 是单线程的,但通过事件循环和异步编程实现高并发。
- 非阻塞 I/O:Node.js 使用非阻塞 I/O 模型,避免了传统多线程编程中的复杂性。
- 高性能:基于 V8 引擎,Node.js 的性能非常出色。
- 跨平台:支持 Windows、Linux 和 macOS。
2. 核心模块
Node.js 提供了一系列内置模块,用于处理文件系统、网络请求、路径解析等常见任务。
fs 模块
1 2 3 4 5
| const fs = require('fs'); fs.readFile('example.txt', 'utf8', (err, data) => { if (err) throw err; console.log(data); });
|
http 模块
1 2 3 4 5 6 7 8
| const http = require('http'); const server = http.createServer((req, res) => { res.writeHead(200, { 'Content-Type': 'text/plain' }); res.end('Hello, World!'); }); server.listen(3000, () => { console.log('Server running at http://localhost:3000'); });
|
path 模块
1 2
| const path = require('path'); console.log(path.join('/foo', 'bar', 'baz'));
|
os 模块
1 2
| const os = require('os'); console.log(os.platform());
|
events 模块
- 提供事件发射器(
EventEmitter),用于创建自定义事件。
1 2 3 4 5 6 7
| const EventEmitter = require('events'); class MyEmitter extends EventEmitter {} const myEmitter = new MyEmitter(); myEmitter.on('event', () => { console.log('Event triggered'); }); myEmitter.emit('event');
|
3. 异步编程
Node.js 的核心是异步编程,通过回调函数、Promise 和 async/await 实现。
- 回调函数
1 2 3 4
| fs.readFile('example.txt', 'utf8', (err, data) => { if (err) throw err; console.log(data); });
|
- Promise
1 2 3 4 5 6
| const readFilePromise = fs.promises.readFile('example.txt', 'utf8'); readFilePromise.then(data => { console.log(data); }).catch(err => { console.error(err); });
|
async/await
1 2 3 4 5 6 7 8 9
| async function readFile() { try { const data = await fs.promises.readFile('example.txt', 'utf8'); console.log(data); } catch (err) { console.error(err); } } readFile();
|
4. 事件循环和非阻塞 I/O
Node.js 的事件循环是其异步编程的核心机制。
- 事件循环
- 事件循环通过监听任务队列(宏任务队列和微任务队列)来执行异步任务。
- 宏任务(如
setTimeout、setInterval)和微任务(如 Promise、queueMicrotask)的执行顺序决定了代码的运行逻辑。
- 非阻塞 I/O
- Node.js 使用非阻塞 I/O 模型,避免了传统 I/O 操作中的阻塞问题。
- 通过回调函数或 Promise 处理 I/O 操作的结果。
5. 模块系统
Node.js 使用 CommonJS 模块系统,通过 require 和 module.exports 导入和导出模块。
- 导出模块
1 2 3 4 5
| function sayHello(name) { return `Hello, ${name}!`; } module.exports = { sayHello };
|
- 导入模块
1 2
| const { sayHello } = require('./myModule'); console.log(sayHello('John'));
|
6. 包管理
Node.js 使用 npm(Node Package Manager)作为包管理工具,用于安装和管理依赖。
7. 常用框架和工具
Node.js 拥有丰富的生态系统,提供了许多流行的框架和工具。
- Express
- 一个轻量级的 Web 框架,用于构建 HTTP 服务器。
1 2 3 4 5 6 7 8
| const express = require('express'); const app = express(); app.get('/', (req, res) => { res.send('Hello, Express!'); }); app.listen(3000, () => { console.log('Server running at http://localhost:3000'); });
|
- Koa
- 由 Express 团队开发的下一代 Web 框架,基于
async/await 设计。
- Mongoose
- 一个 MongoDB ORM,用于操作 MongoDB 数据库。
- Nodemon
- 一个开发工具,用于自动重启 Node.js 应用程序。
8. 调试和性能优化
Node.js 提供了多种工具和方法用于调试和优化性能。
- 调试工具
- 使用
node --inspect 启动 Node.js 应用程序,然后通过 Chrome DevTools 进行调试。
- 性能分析
- 使用
--prof 和 --prof-process 生成性能分析报告。
- 日志和监控
- 使用
winston 或 morgan 等库记录日志。
- 使用
pm2 管理和监控 Node.js 应用程序。
9. 安全性
Node.js 提供了多种机制用于保障应用程序的安全性。
- HTTPS
- 使用
https 模块创建安全的 HTTP 服务器。
1 2 3 4 5 6 7 8 9 10 11 12
| const https = require('https'); const fs = require('fs'); const server = https.createServer({ key: fs.readFileSync('key.pem'), cert: fs.readFileSync('cert.pem') }, (req, res) => { res.writeHead(200); res.end('Hello, HTTPS!'); }); server.listen(3000, () => { console.log('HTTPS server running at https://localhost:3000'); });
|
- 输入验证
- 使用
express-validator 等库验证用户输入。
- 安全头
- 使用
helmet 等库设置安全的 HTTP 头。
10. 部署
Node.js 应用程序可以通过多种方式部署到生产环境。
- 使用 PM2
- PM2 是一个流行的 Node.js 进程管理器,用于监控和管理 Node.js 应用程序。
1 2 3 4
| pm2 start app.js pm2 restart app.js pm2 stop app.js pm2 delete app.js
|
- 使用 Docker
- 将 Node.js 应用程序打包为 Docker 容器,便于部署和管理。
总结
Node.js 是一个功能强大的 JavaScript 运行时环境,适用于构建高性能的服务器端应用程序。通过掌握其核心模块、异步编程机制、事件驱动模型和生态系统,开发者可以高效地开发和部署 Node.js 应用程序。