Node.js 高级特性与性能优化
异步编程模式、流处理、集群与 Worker、性能调优与安全实践。
1. Node.js 高级特性
1.1 异步编程进阶
1.1.1 Async/Await 最佳实践
// 串行执行
async function serialExecution() {
const result1 = await fetchData('url1');
const result2 = await fetchData('url2');
return { result1, result2 };
}
// 并行执行
async function parallelExecution() {
const [result1, result2] = await Promise.all([fetchData('url1'), fetchData('url2')]);
return { result1, result2 };
}
// 带超时的并行执行
async function parallelWithTimeout() {
try {
const [result1, result2] = await Promise.all([
Promise.race([
fetchData('url1'),
new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), 5000)),
]),
fetchData('url2'),
]);
return { result1, result2 };
} catch (error) {
console.error('Error:', error);
return { error: error.message };
}
}
1.1.2 事件循环深入理解
// 事件循环示例
console.log('Start');
setTimeout(() => {
console.log('Timeout');
}, 0);
Promise.resolve().then(() => {
console.log('Promise');
});
console.log('End');
// 输出顺序: Start -> End -> Promise -> Timeout
1.2 流 (Streams)
1.2.1 可读流
const fs = require('fs');
// 创建可读流
const readableStream = fs.createReadStream('large-file.txt');
// 监听数据事件
readableStream.on('data', (chunk) => {
console.log(`Received ${chunk.length} bytes of data`);
});
// 监听结束事件
readableStream.on('end', () => {
console.log('End of file');
});
// 监听错误事件
readableStream.on('error', (error) => {
console.error('Error:', error);
});
1.2.2 可写流
const fs = require('fs');
// 创建可写流
const writableStream = fs.createWriteStream('output.txt');
// 写入数据
writableStream.write('Hello, ');
writableStream.write('Node.js Streams!');
// 结束写入
writableStream.end();
// 监听完成事件
writableStream.on('finish', () => {
console.log('Write completed');
});
1.2.3 管道流
const fs = require('fs');
const zlib = require('zlib');
// 创建可读流
const readableStream = fs.createReadStream('large-file.txt');
// 创建压缩流
const gzipStream = zlib.createGzip();
// 创建可写流
const writableStream = fs.createWriteStream('large-file.txt.gz');
// 使用管道连接流
readableStream.pipe(gzipStream).pipe(writableStream);
// 监听完成事件
writableStream.on('finish', () => {
console.log('File compressed successfully');
});
1.3 集群 (Cluster)
const cluster = require('cluster');
const http = require('http');
const os = require('os');
if (cluster.isMaster) {
console.log(`Master process ${process.pid} is running`);
// 创建工作进程
const numCPUs = os.cpus().length;
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
// 监听工作进程退出
cluster.on('exit', (worker) => {
console.log(`Worker ${worker.process.pid} died`);
// 重启工作进程
cluster.fork();
});
} else {
// 工作进程创建服务器
http
.createServer((req, res) => {
res.writeHead(200);
res.end('Hello from worker ' + process.pid);
})
.listen(8080);
console.log(`Worker ${process.pid} started`);
}
1.4 子进程 (Child Process)
const { spawn, exec, fork } = require('child_process');
// 使用 spawn
const ls = spawn('ls', ['-la']);
ls.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
ls.stderr.on('data', (data) => {
console.error(`stderr: ${data}`);
});
ls.on('close', (code) => {
console.log(`child process exited with code ${code}`);
});
// 使用 exec
exec('ls -la', (error, stdout, stderr) => {
if (error) {
console.error(`error: ${error.message}`);
return;
}
if (stderr) {
console.error(`stderr: ${stderr}`);
return;
}
console.log(`stdout: ${stdout}`);
});
// 使用 fork
const child = fork('./child.js');
child.on('message', (message) => {
console.log('Received from child:', message);
});
child.send({ hello: 'world' });
2. 性能优化
2.1 代码优化
2.1.1 内存管理
// 避免内存泄漏
function createClosure() {
const largeArray = new Array(1000000).fill('data');
return function () {
console.log('Closure created');
// 注意:这里没有引用 largeArray,所以它可以被垃圾回收
};
}
// 正确处理事件监听器
class EventEmitter {
constructor() {
this.listeners = [];
}
on(event, listener) {
this.listeners.push(listener);
return () => {
this.listeners = this.listeners.filter((l) => l !== listener);
};
}
}
// 使用 WeakMap 存储临时数据
const cache = new WeakMap();
function processObject(obj) {
if (cache.has(obj)) {
return cache.get(obj);
}
const result = expensiveOperation(obj);
cache.set(obj, result);
return result;
}
2.1.2 异步操作优化
// 批量处理
async function batchProcess(items, batchSize = 10) {
const results = [];
for (let i = 0; i < items.length; i += batchSize) {
const batch = items.slice(i, i + batchSize);
const batchResults = await Promise.all(batch.map(processItem));
results.push(...batchResults);
}
return results;
}
// 限流
class RateLimiter {
constructor(maxRequests, windowMs) {
this.maxRequests = maxRequests;
this.windowMs = windowMs;
this.requests = [];
}
async limit() {
const now = Date.now();
// 移除过期的请求
this.requests = this.requests.filter((time) => now - time < this.windowMs);
if (this.requests.length >= this.maxRequests) {
// 等待直到有可用的请求名额
const oldestRequest = this.requests[0];
const waitTime = this.windowMs - (now - oldestRequest);
await new Promise((resolve) => setTimeout(resolve, waitTime));
}
this.requests.push(Date.now());
}
}
2.2 网络优化
2.2.1 HTTP/2
const http2 = require('http2');
const fs = require('fs');
// 创建 HTTP/2 服务器
const server = http2.createSecureServer({
key: fs.readFileSync('server.key'),
cert: fs.readFileSync('server.cert')
}
server.on('stream', (stream, headers) => {
stream.respond({
':status': 200,
'content-type': 'text/html'
});
stream.end('<h1>Hello HTTP/2!</h1>');
}
server.listen(8443);
2.2.2 连接池
const mysql = require('mysql2');
// 创建连接池
const pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: 'password',
database: 'mydb',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
}
// 使用连接池
async function query(sql, params) {
return new Promise((resolve, reject) => {
pool.query(sql, params, (error, results) => {
if (error) {
reject(error);
} else {
resolve(results);
}
});
});
}
// 关闭连接池
function closePool() {
pool.end();
}
2.3 缓存策略
2.3.1 内存缓存
class MemoryCache {
constructor() {
this.cache = new Map();
}
set(key, value, ttl = 3600000) {
// 默认 1 小时
const item = {
value,
expiry: Date.now() + ttl,
};
this.cache.set(key, item);
// 设置过期清理
setTimeout(() => {
if (this.cache.has(key)) {
const cachedItem = this.cache.get(key);
if (cachedItem.expiry < Date.now()) {
this.cache.delete(key);
}
}
}, ttl);
}
get(key) {
if (!this.cache.has(key)) {
return null;
}
const item = this.cache.get(key);
if (item.expiry < Date.now()) {
this.cache.delete(key);
return null;
}
return item.value;
}
delete(key) {
this.cache.delete(key);
}
clear() {
this.cache.clear();
}
}
// 使用示例
const cache = new MemoryCache();
cache.set('user:1', { id: 1, name: 'John' });
const user = cache.get('user:1');
2.3.2 Redis 缓存
const redis = require('redis');
// 创建 Redis 客户端
const client = redis.createClient({
url: 'redis://localhost:6379'
}
client.connect();
// 设置缓存
async function setCache(key, value, ttl = 3600) {
try {
await client.set(key, JSON.stringify(value), {
EX: ttl
});
} catch (error) {
console.error('Redis set error:', error);
}
}
// 获取缓存
async function getCache(key) {
try {
const value = await client.get(key);
return value ? JSON.parse(value) : null;
} catch (error) {
console.error('Redis get error:', error);
return null;
}
}
// 删除缓存
async function deleteCache(key) {
try {
await client.del(key);
} catch (error) {
console.error('Redis delete error:', error);
}
}
3. 安全最佳实践
3.1 输入验证
const Joi = require('joi');
// 定义验证模式
const userSchema = Joi.object({
username: Joi.string()
.alphanum()
.min(3)
.max(30)
.required(),
email: Joi.string()
.email({ minDomainSegments: 2, tlds: { allow: ['com', 'net', 'org'] } })
.required(),
password: Joi.string()
.pattern(new RegExp('^[a-zA-Z0-9]{3,30}$'))
.required()
}
// 验证输入
async function validateUser(user) {
try {
const value = await userSchema.validateAsync(user);
return { valid: true, data: value };
} catch (error) {
return { valid: false, error: error.details[0].message };
}
}
3.2 防止注入攻击
const mysql = require('mysql2');
// 使用参数化查询防止 SQL 注入
async function getUserById(id) {
const sql = 'SELECT * FROM users WHERE id = ?';
const [rows] = await pool.execute(sql, [id]);
return rows[0];
}
// 使用 ORM 框架
const Sequelize = require('sequelize');
const sequelize = new Sequelize('database', 'username', 'password', {
host: 'localhost',
dialect: 'mysql'
}
const User = sequelize.define('User', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement:
},
username: Sequelize.STRING,
email: Sequelize.STRING
}
// 安全查询
async function findUser(id) {
return await User.findByPk(id);
}
3.3 身份验证与授权
const jwt = require('jsonwebtoken');
// 生成 JWT
function generateToken(user) {
return jwt.sign({ id: user.id, username: user.username }, process.env.JWT_SECRET, {
expiresIn: '1h',
});
}
// 验证 JWT
function verifyToken(token) {
try {
return jwt.verify(token, process.env.JWT_SECRET);
} catch (error) {
return null;
}
}
// 中间件验证
function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (!token) {
return res.status(401).json({ message: 'Access token required' });
}
const user = verifyToken(token);
if (!user) {
return res.status(403).json({ message: 'Invalid or expired token' });
}
req.user = user;
next();
}
4. 测试与调试
4.1 单元测试
const assert = require('assert');
const { describe, it } = require('mocha');
function sum(a, b) {
return a + b;
}
describe('sum function', () => {
it('should return the sum of two numbers', () => {
assert.strictEqual(sum(1, 2), 3);
assert.strictEqual(sum(-1, 1), 0);
assert.strictEqual(sum(0, 0), 0);
});
});
4.2 性能分析
const { performance } = require('perf_hooks');
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
// 性能分析
const start = performance.now();
const result = fibonacci(30);
const end = performance.now();
console.log(`Fibonacci(30) = ${result}`);
console.log(`Execution time: ${end - start}ms`);
// 使用 clinic 进行更详细的分析
// npm install -g clinic
// clinic doctor -- node app.js
5. 部署与监控
5.1 容器化部署
Dockerfile
from node:16-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY . .
EXPOSE 3000
CMD [ "node", "app.js" ]
docker-compose.yml
version: '3'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=mysql://db:3306/mydb
depends_on:
- db
db:
image: mysql:5.7
environment:
- MYSQL_ROOT_PASSWORD=password
- MYSQL_DATABASE=mydb
volumes:
- mysql-data:/var/lib/mysql
volumes:
mysql-data:
5.2 监控
const prometheus = require('prom-client');
// 创建指标
const httpRequestCounter = new prometheus.Counter({
name: 'http_requests_total',
help: 'Total number of HTTP requests',
labelNames: ['method', 'route', 'status']
}
const httpRequestDuration = new prometheus.Histogram({
name: 'http_request_duration_seconds',
help: 'HTTP request duration in seconds',
labelNames: ['method', 'route'],
buckets: [0.1, 0.5, 1, 2, 5]
}
// 中间件
function prometheusMiddleware(req, res, next) {
const start = Date.now();
res.on('finish', () => {
const duration = (Date.now() - start) / 1000;
httpRequestCounter.inc({
method: req.method,
route: req.path,
status: res.statusCode
});
httpRequestDuration.observe({
method: req.method,
route: req.path
}, duration);
});
next();
}
// 暴露指标端点
app.get('/metrics', async (req, res) => {
res.set('Content-Type', prometheus.register.contentType);
res.end(await prometheus.register.metrics());
}
6. 项目实战
6.1 高性能 API 服务器
const express = require('express');
const cluster = require('cluster');
const os = require('os');
const Redis = require('ioredis');
if (cluster.isMaster) {
// 启动工作进程
const numCPUs = os.cpus().length;
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
} else {
const app = express();
const redis = new Redis();
// 中间件
app.use(express.json());
app.use(prometheusMiddleware);
// 缓存中间件
async function cacheMiddleware(req, res, next) {
const key = `cache:${req.path}`;
const cached = await redis.get(key);
if (cached) {
return res.json(JSON.parse(cached));
}
// 重写 res.json 方法来缓存响应
const originalJson = res.json;
res.json = function (data) {
redis.set(key, JSON.stringify(data), 'EX', 300); // 5分钟缓存
return originalJson.call(this, data);
};
next();
}
// 路由
app.get('/api/users', cacheMiddleware, async (req, res) => {
// 模拟数据库查询
const users = await db.query('SELECT * FROM users');
res.json(users);
});
// 启动服务器
app.listen(3000, () => {
console.log(`Worker ${process.pid} listening on port 3000`);
});
}
7. 常见问题与解决方案
7.1 内存泄漏
问题:Node.js 应用内存使用持续增长 解决方案:
- 使用
node --inspect启动应用,在 Chrome DevTools 中分析内存 - 检查事件监听器是否正确清理
- 避免在循环中创建闭包
- 使用
process.memoryUsage()监控内存使用
7.2 性能瓶颈
问题:应用响应缓慢 解决方案:
- 使用
clinic分析性能瓶颈 - 优化数据库查询,添加索引
- 使用缓存减少重复计算
- 采用异步并行处理
7.3 错误处理
问题:未处理的 Promise 拒绝 解决方案:
- 使用
process.on('unhandledRejection', ...)捕获未处理的 Promise 拒绝 - 在所有 async 函数中使用 try/catch
- 使用错误处理中间件
8. 工具与生态
8.1 开发工具
- Nodemon:自动重启开发服务器
- ESLint:代码质量检查
- Prettier:代码格式化
- Jest:测试框架
- Clinic:性能分析工具
8.2 框架
- Express:轻量级 Web 框架
- Koa:Express 团队开发的下一代框架
- NestJS:基于 TypeScript 的企业级框架
- Fastify:高性能 Web 框架
8.3 数据库 ORM
- Sequelize:支持多种数据库的 ORM
- Prisma:现代数据库工具
- Mongoose:MongoDB ODM
- TypeORM:TypeScript ORM
9. 延伸阅读
- Node.js 官方文档
- Express 文档
- Node.js 设计模式
- 高性能 Node.js
- Node.js 安全最佳实践 通过本教程,你已经了解了 Node.js 的高级特性和性能优化技巧。在实际项目中,你可以根据具体需求选择合适的技术方案,构建高性能、安全、可靠的 Node.js 应用。