外观
NodeJS 笔记
约 1941 字大约 6 分钟
2025-08-16
一、Node.js 基础
1.1 什么是 Node.js?
Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,它允许开发者使用 JavaScript 编写服务器端代码。Node.js 的核心特点:
- 跨平台:可在 Windows、Linux、macOS 等系统上运行
- 事件驱动:采用事件循环机制处理并发
- 非阻塞 I/O:高效处理 I/O 操作,适合高并发场景
- 单线程:基于单线程模型,但通过事件循环实现高并发
// 最简单的 Node.js 服务器
const http = require('http');
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World\n');
});
server.listen(3000, '127.0.0.1', () => {
console.log('服务器运行在 http://127.0.0.1:3000/');
});1.2 Node.js 与浏览器 JavaScript 的区别
| 特性 | 浏览器 JavaScript | Node.js |
|---|---|---|
| 运行环境 | 浏览器 | 服务器 |
| 全局对象 | window | global |
| 模块系统 | ES6 模块、CommonJS (通过 bundler) | CommonJS |
| 核心 API | DOM、BOM | fs、http、path 等 |
| 用途 | 前端交互 | 后端服务、工具开发 |
关键区别:
- Node.js 没有 DOM 和 BOM 相关 API
- Node.js 提供了操作系统级别的 API(如文件系统、网络等)
- Node.js 使用 CommonJS 模块系统(
require/module.exports)
1.3 Node.js 版本管理
- 使用 LTS(长期支持)版本进行生产环境开发
- 推荐使用 nvm(Node Version Manager)管理多个 Node.js 版本
- 常用命令:
nvm install --lts # 安装最新 LTS 版本 nvm use --lts # 使用 LTS 版本 nvm install 18.0.0 # 安装特定版本
二、Node.js 模块系统
2.1 CommonJS 规范
Node.js 采用 CommonJS 模块规范,核心概念:
- 每个文件是一个模块:具有独立的作用域
- 模块缓存:已加载的模块会被缓存,避免重复加载
- 同步加载:模块在代码执行前同步加载
2.2 模块导出
exports 对象
// math.js
exports.add = (a, b) => a + b;
exports.subtract = (a, b) => a - b;
// 使用
const math = require('./math');
console.log(math.add(2, 3)); // 5module.exports
// user.js
module.exports = class User {
constructor(name) {
this.name = name;
}
};
// 使用
const User = require('./user');
const user = new User('John');exports vs module.exports 区别
exports是module.exports的引用- 不能直接给
exports赋值(会断开引用) - 当需要导出单个对象/函数时,使用
module.exports - 当需要导出多个属性时,使用
exports.property
// 正确:给 exports 添加属性
exports.add = (a, b) => a + b;
// 正确:整个替换 module.exports
module.exports = (a, b) => a + b;
// 错误:直接给 exports 赋值(会断开与 module.exports 的引用)
exports = (a, b) => a + b;2.3 模块导入
三种模块类型
// 核心模块(Node.js 内置)
const fs = require('fs');
// 第三方模块(通过 npm 安装)
const express = require('express');
// 自定义模块(本地文件)
const utils = require('./utils');路径解析规则
- 无路径前缀:查找 node_modules
- 以
./或../开头:相对路径 - 以
/开头:绝对路径
三、常用内置模块
3.1 fs 文件系统模块
文件读写
const fs = require('fs');
// 同步读取文件
try {
const data = fs.readFileSync('file.txt', 'utf8');
console.log(data);
} catch (err) {
console.error(err);
}
// 异步读取文件(推荐)
fs.readFile('file.txt', 'utf8', (err, data) => {
if (err) throw err;
console.log(data);
});
// 写入文件
fs.writeFile('output.txt', 'Hello Node.js', (err) => {
if (err) throw err;
console.log('文件已保存');
});常用 fs 方法
| 方法 | 描述 |
|---|---|
fs.readFile() | 异步读取文件 |
fs.readFileSync() | 同步读取文件 |
fs.writeFile() | 异步写入文件 |
fs.writeFileSync() | 同步写入文件 |
fs.appendFile() | 追加内容到文件 |
fs.mkdir() | 创建目录 |
fs.readdir() | 读取目录内容 |
fs.stat() | 获取文件信息 |
最佳实践:
- 优先使用异步方法(避免阻塞事件循环)
- 处理所有可能的错误
- 使用
path模块处理路径(避免跨平台问题)
3.2 path 路径模块
路径拼接
const path = require('path');
// 路径拼接(自动处理分隔符)
const filePath = path.join('/users', 'john', 'docs', 'file.txt');
console.log(filePath); // /users/john/docs/file.txt
// 处理 Windows 路径
const winPath = path.join('C:\\', 'Users', 'John', 'Documents');
console.log(winPath); // C:\Users\John\Documents路径解析
const filePath = '/users/john/docs/file.txt';
console.log(path.dirname(filePath)); // /users/john/docs
console.log(path.basename(filePath)); // file.txt
console.log(path.extname(filePath)); // .txt
// 获取文件名(不含扩展名)
console.log(path.basename(filePath, path.extname(filePath))); // file常用 path 方法
| 方法 | 描述 |
|---|---|
path.join() | 拼接路径片段 |
path.resolve() | 将相对路径解析为绝对路径 |
path.dirname() | 获取目录名 |
path.basename() | 获取文件名 |
path.extname() | 获取文件扩展名 |
path.isAbsolute() | 检查是否为绝对路径 |
3.3 http 模块
创建 HTTP 服务器
const http = require('http');
const server = http.createServer((req, res) => {
// 设置响应头
res.writeHead(200, { 'Content-Type': 'text/plain' });
// 写入响应体
res.write('Hello, ');
// 结束响应
setTimeout(() => {
res.end('World!');
}, 500);
});
server.listen(3000, () => {
console.log('服务器运行在 http://localhost:3000/');
});处理不同路由
const server = http.createServer((req, res) => {
if (req.url === '/') {
res.end('首页');
} else if (req.url === '/about') {
res.end('关于页面');
} else {
res.writeHead(404);
res.end('页面不存在');
}
});获取查询参数
const url = require('url');
const server = http.createServer((req, res) => {
const parsedUrl = url.parse(req.url, true);
const query = parsedUrl.query;
if (parsedUrl.pathname === '/search') {
res.end(`搜索关键词: ${query.q}`);
}
});3.4 events 模块
事件触发与监听
const EventEmitter = require('events');
// 创建事件发射器
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
// 注册事件监听器
myEmitter.on('event', (arg1, arg2) => {
console.log('事件触发:', arg1, arg2);
});
// 触发事件
myEmitter.emit('event', 'a', 'b');常用事件方法
| 方法 | 描述 |
|---|---|
on(event, listener) | 添加事件监听器 |
once(event, listener) | 添加一次性事件监听器 |
emit(event[, ...args]) | 触发事件 |
removeListener(event, listener) | 移除事件监听器 |
setMaxListeners(n) | 设置最大监听器数量 |
实用场景:
- 自定义事件系统
- 实现观察者模式
- 处理异步操作完成
四、npm 包管理
4.1 package.json
初始化项目
npm init -y # 快速创建 package.json关键字段说明
{
"name": "my-app",
"version": "1.0.0",
"description": "My awesome app",
"main": "index.js",
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js"
},
"dependencies": {
"express": "^4.17.1"
},
"devDependencies": {
"nodemon": "^2.0.7"
}
}4.2 常用 npm 命令
安装依赖
# 安装生产依赖
npm install express
# 安装开发依赖
npm install --save-dev nodemon
# 全局安装
npm install -g create-react-app管理依赖
# 更新包
npm update express
# 卸载包
npm uninstall express
# 查看过期的包
npm outdated运行脚本
# 运行 package.json 中定义的脚本
npm run dev
# 运行 start 脚本(特殊,可省略 run)
npm start4.3 语义化版本控制
^1.2.3:允许更新到最新兼容版本(1.x.x)~1.2.3:允许更新到最新补丁版本(1.2.x)1.2.3:精确匹配指定版本
五、实用技巧与最佳实践
5.1 错误处理
异步错误处理
// 回调方式
fs.readFile('file.txt', (err, data) => {
if (err) {
console.error('读取文件出错:', err);
return;
}
console.log(data);
});
// Promise 方式
const fs = require('fs').promises;
async function readFile() {
try {
const data = await fs.readFile('file.txt', 'utf8');
console.log(data);
} catch (err) {
console.error('读取文件出错:', err);
}
}错误类型判断
try {
// 可能出错的代码
} catch (err) {
if (err.code === 'ENOENT') {
console.error('文件不存在');
} else {
console.error('其他错误:', err);
}
}5.2 调试技巧
console 调试
// 基本日志
console.log('普通日志');
console.info('信息日志');
console.warn('警告日志');
console.error('错误日志');
// 格式化输出
console.log('用户 %s 年龄 %d', 'John', 30);
// 对象检查
console.dir(obj, { depth: null, colors: true });
// 性能测试
console.time('operation');
// 执行操作
console.timeEnd('operation');使用 Node.js 调试器
# 启动调试
node inspect app.js
# 在代码中设置断点
debugger;Chrome DevTools 调试
# 启动调试
node --inspect app.js
# 或
node --inspect-brk app.js # 在第一行暂停
# 打开 Chrome 浏览器
# 访问 chrome://inspect
# 点击 "Open dedicated DevTools for Node"5.3 代码组织
模块化设计
// utils/string.js
exports.capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1);
// utils/array.js
exports.unique = (arr) => [...new Set(arr)];
// app.js
const { capitalize } = require('./utils/string');
const { unique } = require('./utils/array');项目结构建议
my-app/
├── node_modules/ # 依赖包
├── src/ # 源代码
│ ├── config/ # 配置文件
│ ├── controllers/ # 控制器
│ ├── models/ # 数据模型
│ ├── routes/ # 路由
│ ├── services/ # 业务逻辑
│ ├── utils/ # 工具函数
│ └── index.js # 入口文件
├── tests/ # 测试代码
├── public/ # 静态资源
├── .env # 环境变量
└── package.json5.4 环境变量管理
使用 dotenv 模块
npm install dotenv// 在应用最开始加载
require('dotenv').config();
// 使用环境变量
const dbHost = process.env.DB_HOST;
const dbUser = process.env.DB_USER;
const dbPass = process.env.DB_PASS;.env 文件示例
DB_HOST=localhost
DB_USER=root
DB_PASS=secret
PORT=3000最佳实践:
- 不要将 .env 文件提交到版本控制
- 在 .gitignore 中添加 .env
- 为环境变量提供默认值
- 使用 NODE_ENV 区分开发和生产环境
