Skip to content
On this page

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      │
   └───────────────────────────┘
  1. 定时器阶段 (Timers): 执行由setTimeout()和setInterval()设置的回调
  2. 待定回调 (Pending callbacks): 执行延迟到下一个循环迭代的I/O回调
  3. 空闲/准备 (Idle, prepare): 仅供内部使用
  4. 轮询阶段 (Poll): 检索新的I/O事件;执行I/O相关回调
  5. 检测阶段 (Check): 执行setImmediate()设置的回调
  6. 关闭回调 (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应用程序的核心架构。