一、Node.js 简介与安装
1.1 什么是 Node.js?
Node.js 是一个基于 Chrome V8 JavaScript 引擎的 JavaScript 运行时环境,让 JavaScript 可以脱离浏览器在服务器端执行。它的主要特点包括:
- 事件驱动:采用观察者模式,通过事件循环处理异步操作
- 非阻塞 I/O:使用异步编程模型,提高并发处理能力
- 单线程:通过事件循环处理并发,避免多线程编程的复杂性
1.2 安装 Node.js
访问 Node.js 官网下载安装包,推荐选择 LTS(长期支持)版本。安装完成后,在终端验证:
node -v # 查看 Node.js 版本
npm -v # 查看 npm 版本
提示: npm(Node Package Manager)是 Node.js 的包管理工具,随 Node.js 一起安装。
二、JavaScript 基础回顾
学习 Node.js 前,需要掌握以下 JavaScript 核心概念:
2.1 ES6+ 重要特性
- 箭头函数:
() => {} - 解构赋值:
const {name, age} = user - 模板字符串:
`Hello, ${name}!` - let/const:块级作用域变量声明
2.2 异步编程基础
Node.js 的核心优势在于异步非阻塞 I/O,需掌握以下异步编程方式:
回调函数(Callback)
const fs = require('fs');
fs.readFile('file.txt', 'utf8', (err, data) => {
if (err) {
console.error('读取文件出错:', err);
return;
}
console.log('文件内容:', data);
});
Promise
const readFilePromise = new Promise((resolve, reject) => {
fs.readFile('file.txt', 'utf8', (err, data) => {
if (err) reject(err);
else resolve(data);
});
});
readFilePromise
.then(data => console.log(data))
.catch(err => console.error(err));
Async/Await(推荐)
async function readFileAsync() {
try {
const data = await fs.promises.readFile('file.txt', 'utf8');
console.log(data);
} catch (err) {
console.error(err);
}
}
readFileAsync();
三、Node.js 核心模块
Node.js 提供了丰富的内置模块,无需安装即可使用:
| 模块名 | 功能描述 | 常用方法/类 |
|---|---|---|
fs |
文件系统操作 | readFile, writeFile, createReadStream |
path |
路径处理 | join, resolve, dirname |
http |
HTTP 服务器/客户端 | createServer, request |
events |
事件处理 | EventEmitter, on, emit |
os |
操作系统信息 | platform, arch, cpus |
url |
URL 解析 | parse, format |
3.1 文件系统操作示例
const fs = require('fs');
const path = require('path');
// 路径拼接
const filePath = path.join(__dirname, 'files', 'test.txt');
// 异步读取文件
fs.readFile(filePath, 'utf8', (err, data) => {
if (err) throw err;
console.log('文件内容:', data);
});
// 同步读取文件
try {
const data = fs.readFileSync(filePath, 'utf8');
console.log('文件内容:', data);
} catch (err) {
console.error('读取文件出错:', err);
}
3.2 创建 HTTP 服务器
const http = require('http');
const server = http.createServer((req, res) => {
// 设置响应头
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
// 根据 URL 路由处理
if (req.url === '/') {
res.end('<h1>首页</h1><p>欢迎访问我的网站!</p>');
} else if (req.url === '/about') {
res.end('<h1>关于我们</h1>');
} else {
res.writeHead(404);
res.end('<h1>页面未找到</h1>');
}
});
server.listen(3000, () => {
console.log('服务器运行在 http://localhost:3000');
});
四、模块系统与 NPM
4.1 CommonJS 模块规范
Node.js 使用 CommonJS 模块系统:
导出模块(math.js)
// 方法一:通过 exports 导出
exports.add = (a, b) => a + b;
exports.subtract = (a, b) => a - b;
// 方法二:通过 module.exports 导出
const multiply = (a, b) => a * b;
const divide = (a, b) => a / b;
module.exports = {
multiply,
divide
};
导入模块(app.js)
const { add, subtract } = require('./math');
const math = require('./math'); // 导入整个模块
console.log(add(5, 3)); // 8
console.log(math.multiply(4, 5)); // 20
4.2 包管理与 NPM
npm 是 Node.js 的包管理工具,用于安装和管理第三方模块:
# 初始化项目(生成 package.json)
npm init -y
# 安装包
npm install express # 本地安装
npm install -g nodemon # 全局安装
npm install jest --save-dev # 开发依赖
# 卸载包
npm uninstall express
# 查看已安装的包
npm list
package.json 重要字段:
dependencies:生产环境依赖devDependencies:开发环境依赖scripts:自定义命令脚本
五、Express 框架
Express 是 Node.js 最流行的 Web 框架,简化了 HTTP 服务器开发。
5.1 基本使用
const express = require('express');
const app = express();
const port = 3000;
// 解析 application/json
app.use(express.json());
// 解析 application/x-www-form-urlencoded
app.use(express.urlencoded({ extended: true }));
// 静态文件服务
app.use(express.static('public'));
// 路由定义
app.get('/', (req, res) => {
res.send('首页');
});
app.get('/users/:id', (req, res) => {
const userId = req.params.id;
res.send(`用户 ID: ${userId}`);
});
app.post('/users', (req, res) => {
const userData = req.body;
// 处理用户创建逻辑
res.json({ message: '用户创建成功', data: userData });
});
app.listen(port, () => {
console.log(`Express 服务器运行在 http://localhost:${port}`);
});
5.2 中间件(Middleware)
中间件是在请求-响应周期中执行的函数:
// 日志中间件
app.use((req, res, next) => {
console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
next(); // 调用下一个中间件
});
// 身份验证中间件
const authMiddleware = (req, res, next) => {
const token = req.headers.authorization;
if (token === 'valid_token') {
next();
} else {
res.status(401).json({ error: '未授权访问' });
}
};
// 路由特定中间件
app.get('/admin', authMiddleware, (req, res) => {
res.send('管理员页面');
});
// 错误处理中间件
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('服务器内部错误!');
});
5.3 路由模块化
routes/users.js
const express = require('express');
const router = express.Router();
// GET /users
router.get('/', (req, res) => {
res.send('用户列表');
});
// GET /users/:id
router.get('/:id', (req, res) => {
res.send(`用户详情: ${req.params.id}`);
});
// POST /users
router.post('/', (req, res) => {
res.json({ message: '创建用户' });
});
module.exports = router;
主文件 app.js
const express = require('express');
const app = express();
const userRoutes = require('./routes/users');
app.use('/users', userRoutes);
// ... 其他配置
六、数据库操作
6.1 MongoDB 与 Mongoose
MongoDB 是常用的 NoSQL 数据库,Mongoose 是 MongoDB 的对象文档建模工具(ODM):
const mongoose = require('mongoose');
// 连接数据库
mongoose.connect('mongodb://localhost:27017/mydatabase', {
useNewUrlParser: true,
useUnifiedTopology: true
});
// 定义用户模式(Schema)
const userSchema = new mongoose.Schema({
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
age: { type: Number, min: 0 }
}, { timestamps: true });
// 创建模型(Model)
const User = mongoose.model('User', userSchema);
// 使用模型进行 CRUD 操作
async function createUser() {
try {
const user = new User({
name: '张三',
email: 'zhangsan@example.com',
age: 25
});
await user.save();
console.log('用户创建成功:', user);
} catch (error) {
console.error('创建用户失败:', error.message);
}
}
// 查询用户
async function getUsers() {
try {
const users = await User.find({ age: { $gte: 18 } }); // 年龄大于等于18岁的用户
console.log(users);
} catch (error) {
console.error('查询用户失败:', error.message);
}
}
createUser();
getUsers();
6.2 MySQL 与 Sequelize
Sequelize 是基于 Promise 的 Node.js ORM,支持多种 SQL 数据库:
const { Sequelize, DataTypes } = require('sequelize');
// 连接数据库
const sequelize = new Sequelize('database', 'username', 'password', {
host: 'localhost',
dialect: 'mysql'
});
// 定义用户模型
const User = sequelize.define('User', {
name: { type: DataTypes.STRING, allowNull: false },
email: { type: DataTypes.STRING, unique: true }
});
// 同步模型到数据库
async function syncDatabase() {
try {
await sequelize.authenticate();
console.log('数据库连接成功');
await sequelize.sync(); // 创建表(如果不存在)
console.log('所有模型同步成功');
} catch (error) {
console.error('数据库操作失败:', error);
}
}
syncDatabase();
七、异步编程与事件循环
7.1 Node.js 事件循环(Event Loop)
事件循环是 Node.js 实现非阻塞 I/O 的核心机制:
// 示例:理解事件循环的不同阶段
console.log('开始');
// 下一轮事件循环执行
setImmediate(() => {
console.log('setImmediate');
});
// 当前轮次结束后执行
process.nextTick(() => {
console.log('nextTick');
});
// 定时器阶段
setTimeout(() => {
console.log('setTimeout 0ms');
}, 0);
// Promise 微任务
Promise.resolve().then(() => {
console.log('Promise');
});
console.log('结束');
// 执行顺序:
// 开始 → 结束 → nextTick → Promise → setTimeout 0ms → setImmediate
7.2 EventEmitter 事件机制
const EventEmitter = require('events');
// 创建自定义事件发射器
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
// 注册事件监听器
myEmitter.on('event', (data) => {
console.log('事件触发,数据:', data);
});
// 一次性事件监听
myEmitter.once('onceEvent', () => {
console.log('这个事件只触发一次');
});
// 触发事件
myEmitter.emit('event', { message: 'Hello' });
myEmitter.emit('event', { message: 'World' });
myEmitter.emit('onceEvent'); // 触发
myEmitter.emit('onceEvent'); // 不触发
事件循环阶段:
- timers:执行 setTimeout 和 setInterval 回调
- pending callbacks:执行系统操作的回调
- idle, prepare:内部使用
- poll:检索新的 I/O 事件
- check:执行 setImmediate 回调
- close callbacks:执行关闭事件的回调(如 socket.close)
八、流(Streams)与缓冲区(Buffer)
8.1 流的基本概念
流是处理读写数据的高效方式,特别适合大文件操作:
const fs = require('fs');
// 创建可读流
const readableStream = fs.createReadStream('largefile.txt', {
encoding: 'utf8',
highWaterMark: 1024 * 1024 // 每次读取 1MB
});
// 创建可写流
const writableStream = fs.createWriteStream('copy.txt');
// 管道操作(自动管理数据流)
readableStream.pipe(writableStream);
// 或者手动处理数据流
readableStream.on('data', (chunk) => {
console.log(`接收到 ${chunk.length} 字节的数据`);
writableStream.write(chunk);
});
readableStream.on('end', () => {
console.log('文件读取完成');
writableStream.end();
});
readableStream.on('error', (err) => {
console.error('读取文件出错:', err);
});
8.2 Buffer 处理二进制数据
// 创建 Buffer
const buf1 = Buffer.alloc(10); // 创建长度为10的Buffer,填充0
const buf2 = Buffer.from('Hello'); // 从字符串创建Buffer
const buf3 = Buffer.from([1, 2, 3]); // 从数组创建Buffer
// Buffer 操作
console.log(buf2.toString()); // "Hello"
console.log(buf2.toString('base64')); // Base64 编码
// Buffer 拼接
const buf4 = Buffer.concat([buf2, Buffer.from(' World')]);
console.log(buf4.toString()); // "Hello World"
// 写入 Buffer
const buf5 = Buffer.alloc(256);
const len = buf5.write('Node.js 学习笔记');
console.log(`写入字节数: ${len}`);
注意: 流处理可以显著降低内存占用,特别是在处理大文件时。应当优先使用流而不是一次性读取整个文件。
九、调试与测试
9.1 调试工具
Node.js 提供内置调试器和 Chrome DevTools 支持:
// 使用 console.log 调试
console.log('变量值:', variable);
// 使用 console.time 计时
console.time('操作耗时');
// 执行某些操作
console.timeEnd('操作耗时'); // 输出: 操作耗时: 15.234ms
// 使用 debugger 语句
function complexCalculation(a, b) {
debugger; // 在此处设置断点
return a * b + Math.sqrt(a + b);
}
// 启动调试: node --inspect-brk app.js
9.2 单元测试
使用 Jest 进行单元测试:
// math.js
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
module.exports = { add, subtract };
// math.test.js
const { add, subtract } = require('./math');
test('加法测试', () => {
expect(add(1, 2)).toBe(3);
expect(add(0.1, 0.2)).toBeCloseTo(0.3);
});
test('减法测试', () => {
expect(subtract(5, 3)).toBe(2);
});
// 异步测试
test('异步数据获取', async () => {
const data = await fetchData();
expect(data).toBeDefined();
});
十、项目实战与部署
10.1 项目结构规划
my-node-app/
├── src/
│ ├── controllers/ # 控制器
│ ├── models/ # 数据模型
│ ├── routes/ # 路由
│ ├── middleware/ # 中间件
│ ├── utils/ # 工具函数
│ └── app.js # 应用入口
├── config/ # 配置文件
├── public/ # 静态文件
├── tests/ # 测试文件
├── node_modules/ # 依赖包
├── package.json
└── README.md
10.2 使用 PM2 进行进程管理
PM2 是 Node.js 应用的生产环境进程管理器:
# 安装 PM2
npm install -g pm2
# 启动应用
pm2 start app.js --name "my-app"
# 常用命令
pm2 list # 查看所有进程
pm2 logs my-app # 查看日志
pm2 restart my-app # 重启应用
pm2 stop my-app # 停止应用
pm2 delete my-app # 删除应用
# 开机自启
pm2 startup
pm2 save
10.3 环境变量与配置管理
// 安装 dotenv: npm install dotenv
require('dotenv').config();
const config = {
port: process.env.PORT || 3000,
database: {
host: process.env.DB_HOST || 'localhost',
port: process.env.DB_PORT || 27017,
name: process.env.DB_NAME || 'mydatabase'
},
jwtSecret: process.env.JWT_SECRET || 'default-secret'
};
module.exports = config;
实战练习:构建 RESTful API
创建一个完整的用户管理系统 API,包含以下功能:
- 用户注册(POST /api/register)
- 用户登录(POST /api/login)
- 获取用户列表(GET /api/users)
- 获取用户详情(GET /api/users/:id)
- 更新用户信息(PUT /api/users/:id)
- 删除用户(DELETE /api/users/:id)
技术要求: Express 框架、MongoDB 数据库、JWT 认证、输入验证、错误处理、单元测试。
十一、学习路线与资源推荐
学习路线图
- 第一阶段(1-2周):JavaScript 基础 → Node.js 基础 → 核心模块
- 第二阶段(2-3周):Express 框架 → 数据库操作 → 用户认证
- 第三阶段(2-3周):实时应用 → 测试调试 → 性能优化
- 第四阶段(持续):项目实战 → 源码阅读 → 架构设计
推荐资源
- 官方文档:Node.js 官方文档
- 在线教程:MDN Web Docs、FreeCodeCamp Node.js 教程
- 书籍:《Node.js 设计模式》、《深入浅出 Node.js》
- 视频课程:黑马程序员 Node.js 全套教程
学习建议: 理论学习与项目实践相结合,从简单项目开始逐步增加复杂度。参与开源项目、阅读优质源码是提升技能的有效途径。