Appearance
Node.js 完全指南
目录
Node.js 简介
什么是 Node.js
Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时环境。它使得开发者可以使用 JavaScript 来编写服务器端程序。Node.js 采用事件驱动、非阻塞 I/O 模型,使其轻量且高效。
特点
单线程事件循环
- 基于事件驱动
- 非阻塞 I/O
- 高并发处理能力
跨平台
- 支持 Windows、macOS、Linux
- 统一的 API
- 良好的可移植性
强大的生态系统
- npm 包管理器
- 大量的第三方模块
- 活跃的社区
核心概念
1. 事件循环
javascript
console.log("开始");
setTimeout(() => {
console.log("定时器");
}, 0);
Promise.resolve().then(() => {
console.log("Promise");
});
process.nextTick(() => {
console.log("nextTick");
});
console.log("结束");
// 输出顺序:
// 开始
// 结束
// nextTick
// Promise
// 定时器
2. 回调函数
javascript
const fs = require("fs");
fs.readFile("example.txt", "utf8", (err, data) => {
if (err) {
console.error("读取文件失败:", err);
return;
}
console.log("文件内容:", data);
});
3. Promise
javascript
const fs = require("fs").promises;
async function readFile() {
try {
const data = await fs.readFile("example.txt", "utf8");
console.log("文件内容:", data);
} catch (err) {
console.error("读取文件失败:", err);
}
}
readFile();
基础模块
1. 文件系统 (fs)
javascript
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);
});
// Promise 方式
const fsPromises = require("fs").promises;
async function readFileAsync() {
try {
const data = await fsPromises.readFile("file.txt", "utf8");
console.log(data);
} catch (err) {
console.error(err);
}
}
2. 路径处理 (path)
javascript
const path = require("path");
// 路径拼接
console.log(path.join("/user", "files", "example.txt"));
// 获取绝对路径
console.log(path.resolve("example.txt"));
// 路径解析
console.log(path.parse("/user/files/example.txt"));
3. HTTP 模块
javascript
const http = require("http");
const server = http.createServer((req, res) => {
res.writeHead(200, { "Content-Type": "text/plain" });
res.end("Hello World\n");
});
server.listen(3000, () => {
console.log("服务器运行在 http://localhost:3000/");
});
异步编程
1. Callback 方式
javascript
function fetchData(callback) {
setTimeout(() => {
callback(null, { data: "some data" });
}, 1000);
}
fetchData((err, result) => {
if (err) {
console.error(err);
return;
}
console.log(result);
});
2. Promise 方式
javascript
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ data: "some data" });
}, 1000);
});
}
fetchData()
.then((result) => console.log(result))
.catch((err) => console.error(err));
3. Async/Await 方式
javascript
async function getData() {
try {
const result = await fetchData();
console.log(result);
} catch (err) {
console.error(err);
}
}
getData();
模块系统
1. CommonJS 模块
javascript
// math.js
module.exports = {
add: (a, b) => a + b,
subtract: (a, b) => a - b,
};
// main.js
const math = require("./math");
console.log(math.add(2, 3));
2. ES 模块
javascript
// math.mjs
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
// main.mjs
import { add, subtract } from "./math.mjs";
console.log(add(2, 3));
包管理
1. NPM 基础命令
bash
# 初始化项目
npm init
# 安装依赖
npm install express
# 安装开发依赖
npm install --save-dev nodemon
# 更新依赖
npm update
# 删除依赖
npm uninstall express
2. package.json
json
{
"name": "my-node-app",
"version": "1.0.0",
"description": "My Node.js application",
"main": "index.js",
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js",
"test": "jest"
},
"dependencies": {
"express": "^4.17.1"
},
"devDependencies": {
"nodemon": "^2.0.7",
"jest": "^27.0.6"
}
}
事件驱动编程
1. EventEmitter
javascript
const EventEmitter = require("events");
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
// 注册事件监听器
myEmitter.on("event", (arg) => {
console.log("事件触发:", arg);
});
// 触发事件
myEmitter.emit("event", "自定义参数");
2. 自定义事件
javascript
class Database extends EventEmitter {
query(sql) {
// 模拟数据库查询
setTimeout(() => {
this.emit("result", { rows: [{ id: 1 }] });
}, 1000);
}
}
const db = new Database();
db.on("result", (result) => {
console.log("查询结果:", result);
});
db.query("SELECT * FROM users");
文件系统操作
1. 文件读写
javascript
const fs = require("fs").promises;
async function fileOperations() {
// 写入文件
await fs.writeFile("test.txt", "你好,Node.js");
// 读取文件
const content = await fs.readFile("test.txt", "utf8");
console.log("文件内容:", content);
// 追加内容
await fs.appendFile("test.txt", "\n新的一行");
// 检查文件是否存在
try {
await fs.access("test.txt");
console.log("文件存在");
} catch {
console.log("文件不存在");
}
}
2. 目录操作
javascript
const fs = require("fs").promises;
async function directoryOperations() {
// 创建目录
await fs.mkdir("new-folder", { recursive: true });
// 读取目录内容
const files = await fs.readdir("new-folder");
console.log("目录内容:", files);
// 删除目录
await fs.rmdir("new-folder");
}
网络编程
1. HTTP 服务器
javascript
const http = require("http");
const server = http.createServer((req, res) => {
// 设置响应头
res.setHeader("Content-Type", "application/json");
// 路由处理
if (req.url === "/api/users" && req.method === "GET") {
res.statusCode = 200;
res.end(JSON.stringify({ users: [] }));
} else {
res.statusCode = 404;
res.end(JSON.stringify({ error: "Not Found" }));
}
});
server.listen(3000, () => {
console.log("服务器运行在 http://localhost:3000/");
});
2. WebSocket
javascript
const WebSocket = require("ws");
const wss = new WebSocket.Server({ port: 8080 });
wss.on("connection", (ws) => {
console.log("新的连接");
ws.on("message", (message) => {
console.log("收到:", message);
ws.send(`服务器收到: ${message}`);
});
ws.send("欢迎连接 WebSocket 服务器");
});
进程和线程
1. 子进程
javascript
const { spawn } = require("child_process");
// 执行系统命令
const ls = spawn("ls", ["-l"]);
ls.stdout.on("data", (data) => {
console.log(`输出:${data}`);
});
ls.stderr.on("data", (data) => {
console.error(`错误:${data}`);
});
ls.on("close", (code) => {
console.log(`子进程退出码:${code}`);
});
2. 集群
javascript
const cluster = require("cluster");
const http = require("http");
const numCPUs = require("os").cpus().length;
if (cluster.isMaster) {
console.log(`主进程 ${process.pid} 正在运行`);
// 衍生工作进程
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on("exit", (worker, code, signal) => {
console.log(`工作进程 ${worker.process.pid} 已退出`);
});
} else {
// 工作进程可以共享任何 TCP 连接
http
.createServer((req, res) => {
res.writeHead(200);
res.end("你好世界\n");
})
.listen(8000);
console.log(`工作进程 ${process.pid} 已启动`);
}
调试和性能优化
1. 调试
javascript
// 使用 debugger 语句
function calculate(x, y) {
debugger;
return x + y;
}
// 使用 console
console.log("普通日志");
console.error("错误日志");
console.warn("警告日志");
console.time("计时器");
console.timeEnd("计时器");
2. 性能监控
javascript
const { performance, PerformanceObserver } = require("perf_hooks");
// 创建性能观察器
const obs = new PerformanceObserver((list) => {
const entries = list.getEntries();
entries.forEach((entry) => {
console.log(`${entry.name}: ${entry.duration}`);
});
});
obs.observe({ entryTypes: ["measure"] });
// 测量代码性能
performance.mark("A");
// 某些操作
performance.mark("B");
performance.measure("A to B", "A", "B");
最佳实践
1. 错误处理
javascript
// 全局错误处理
process.on("uncaughtException", (err) => {
console.error("未捕获的异常:", err);
// 执行清理操作
process.exit(1);
});
process.on("unhandledRejection", (reason, promise) => {
console.error("未处理的 Promise 拒绝:", reason);
});
// 异步错误处理
async function handleErrors() {
try {
await riskyOperation();
} catch (err) {
console.error("操作失败:", err);
// 适当的错误处理
}
}
2. 安全最佳实践
javascript
// 使用环境变量
require("dotenv").config();
const dbPassword = process.env.DB_PASSWORD;
// 输入验证
const validator = require("validator");
const userInput = "...";
if (!validator.isEmail(userInput)) {
throw new Error("无效的邮箱地址");
}
// 安全的密码存储
const bcrypt = require("bcrypt");
const hashedPassword = await bcrypt.hash(password, 10);
3. 代码组织
javascript
// 模块化
// user/model.js
class User {
constructor(name, email) {
this.name = name;
this.email = email;
}
}
module.exports = User;
// user/controller.js
const User = require("./model");
const UserService = require("./service");
class UserController {
async createUser(req, res) {
try {
const user = await UserService.create(req.body);
res.json(user);
} catch (err) {
res.status(400).json({ error: err.message });
}
}
}
4. 日志记录
javascript
const winston = require("winston");
const logger = winston.createLogger({
level: "info",
format: winston.format.json(),
transports: [
new winston.transports.File({ filename: "error.log", level: "error" }),
new winston.transports.File({ filename: "combined.log" }),
],
});
// 记录日志
logger.info("应用启动");
logger.error("发生错误", { error: "database connection failed" });