Appearance
Node.js 基础概念
Node.js是一个基于Chrome V8引擎的JavaScript运行时,允许开发者使用JavaScript构建服务器端应用程序。本章将详细介绍Node.js的核心概念。
单线程事件循环模型
Node.js使用单线程事件循环模型来处理并发操作。与传统的多线程模型不同,Node.js使用事件驱动和非阻塞I/O操作,使其能够处理大量并发连接。
事件循环的阶段
┌───────────────────────────┐
┌─>│ timers │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
│ │ pending callbacks │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
│ │ idle, prepare │
│ └─────────────┬─────────────┘ ┌───────────────┐
│ ┌─────────────┴─────────────┐ │ incoming: │
│ │ poll │<─────┤ connections, │
│ └─────────────┬─────────────┘ │ data, etc. │
│ ┌─────────────┴─────────────┐ └───────────────┘
│ │ check │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
└──┤ close callbacks │
└───────────────────────────┘
- 定时器阶段 (Timers): 执行由setTimeout()和setInterval()设置的回调
- 待定回调 (Pending callbacks): 执行延迟到下一个循环迭代的I/O回调
- 空闲/准备 (Idle, prepare): 仅供内部使用
- 轮询阶段 (Poll): 检索新的I/O事件;执行I/O相关回调
- 检测阶段 (Check): 执行setImmediate()设置的回调
- 关闭回调 (Close callbacks): 执行close事件的回调
非阻塞I/O
Node.js的非阻塞I/O操作是其高性能的关键:
javascript
const fs = require('fs');
// 阻塞操作示例(不推荐)
const data = fs.readFileSync('/file.txt'); // 程序会等待直到读取完成
console.log('文件内容:', data);
// 非阻塞操作示例(推荐)
fs.readFile('/file.txt', (err, data) => {
if (err) throw err;
console.log('文件内容:', data);
});
console.log('这行会先执行'); // 这行会在文件读取完成前执行
模块系统
Node.js使用CommonJS模块系统:
javascript
// math.js - 导出模块
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
module.exports = {
add,
subtract
};
// app.js - 导入模块
const math = require('./math');
console.log(math.add(2, 3)); // 5
回调函数
回调函数是Node.js中处理异步操作的主要方式:
javascript
function asyncOperation(data, callback) {
// 模拟异步操作
setTimeout(() => {
if (data) {
callback(null, `处理完成: ${data}`);
} else {
callback(new Error('无效数据'));
}
}, 1000);
}
asyncOperation('示例数据', (err, result) => {
if (err) {
console.error('错误:', err.message);
} else {
console.log('结果:', result);
}
});
事件驱动编程
Node.js使用events模块实现事件驱动编程:
javascript
const EventEmitter = require('events');
const emitter = new EventEmitter();
// 注册事件监听器
emitter.on('dataReceived', (data) => {
console.log('接收到数据:', data);
});
// 触发事件
emitter.emit('dataReceived', 'Hello, Node.js!');
Buffer
Buffer用于处理二进制数据:
javascript
// 创建Buffer
const buf1 = Buffer.alloc(10); // 创建10字节的Buffer,初始化为0
const buf2 = Buffer.from('Hello'); // 从字符串创建Buffer
const buf3 = Buffer.from([1, 2, 3, 4]); // 从数组创建Buffer
// Buffer操作
console.log(buf2.toString()); // 'Hello'
console.log(buf3.length); // 4
Stream
Stream是处理流数据的抽象接口:
javascript
const fs = require('fs');
const readline = require('readline');
// 创建可读流
const readStream = fs.createReadStream('input.txt');
// 创建可写流
const writeStream = fs.createWriteStream('output.txt');
// 管道操作
readStream.pipe(writeStream);
// 处理流事件
readStream.on('data', (chunk) => {
console.log('接收到数据块:', chunk.length, '字节');
});
readStream.on('end', () => {
console.log('读取完成');
});
全局对象
Node.js提供了一些全局对象:
global: 全局命名空间对象process: 提供有关当前Node.js进程的信息和控制Buffer: 用于处理二进制数据__dirname: 当前模块的目录名__filename: 当前模块的文件名module: 对当前模块的引用require(): 用于导入模块
进程管理
javascript
// 获取命令行参数
console.log('参数:', process.argv);
// 获取环境变量
console.log('NODE_ENV:', process.env.NODE_ENV);
// 退出进程
process.exit(0);
// 监听进程事件
process.on('exit', (code) => {
console.log(`进程退出,退出码: ${code}`);
});
错误处理
Node.js中的错误处理:
javascript
// 同步错误处理
try {
const data = fs.readFileSync('/nonexistent/file');
} catch (err) {
console.error('同步错误:', err.message);
}
// 异步错误处理
fs.readFile('/nonexistent/file', (err, data) => {
if (err) {
console.error('异步错误:', err.message);
return;
}
console.log(data);
});
// 未捕获异常处理
process.on('uncaughtException', (err) => {
console.error('未捕获异常:', err);
process.exit(1);
});
理解这些基础概念是掌握Node.js开发的关键,它们构成了Node.js应用程序的核心架构。