Skip to content

Node.js 基础 ​

Node.js 概述 ​

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,采用事件驱动、非阻塞 I/O 模型。

特点 ​

  • 单线程:主线程单线程执行,通过事件循环处理异步操作
  • 非阻塞 I/O:文件读写、网络请求等操作不会阻塞主线程
  • 事件驱动:通过事件回调机制处理异步任务

事件循环 (Event Loop) ​

Node.js 的事件循环分为六个阶段,每个阶段都有一个回调队列:

   ┌───────┐
   │  timers  │  ← setTimeout / setInterval 回调
   └───────┘
        │
   ┌───────┐
   │ pending  │  ← 系统级回调(如 TCP 错误)
   │  callbacks │
   └───────┘
        │
   ┌───────┐
   │  idle,   │  ← 内部使用
   │  prepare │
   └───────┘
        │
   ┌───────┐
   │   poll    │  ← I/O 回调、获取新事件(最重要的阶段)
   └───────┘
        │
   ┌───────┐
   │   check   │  ← setImmediate 回调
   └───────┘
        │
   ┌───────┐
   │ close   │  ← 关闭事件回调(如 socket.on('close'))
   │ callbacks│
   └───────┘
   ┌───────┐
   │  timers  │  ← setTimeout / setInterval 回调
   └───────┘
        │
   ┌───────┐
   │ pending  │  ← 系统级回调(如 TCP 错误)
   │  callbacks │
   └───────┘
        │
   ┌───────┐
   │  idle,   │  ← 内部使用
   │  prepare │
   └───────┘
        │
   ┌───────┐
   │   poll    │  ← I/O 回调、获取新事件(最重要的阶段)
   └───────┘
        │
   ┌───────┐
   │   check   │  ← setImmediate 回调
   └───────┘
        │
   ┌───────┐
   │ close   │  ← 关闭事件回调(如 socket.on('close'))
   │ callbacks│
   └───────┘

微任务与宏任务 ​

微任务(每个阶段之间执行):
  process.nextTick → Promise.then / catch / finally

宏任务(事件循环各阶段):
  setTimeout / setInterval → I/O → setImmediate
微任务(每个阶段之间执行):
  process.nextTick → Promise.then / catch / finally

宏任务(事件循环各阶段):
  setTimeout / setInterval → I/O → setImmediate
js
console.log('1')

setTimeout(() => console.log('2'), 0)

setImmediate(() => console.log('3'))

process.nextTick(() => console.log('4'))

Promise.resolve().then(() => console.log('5'))

// 输出顺序:1 → 4 → 5 → 2 → 3
console.log('1')

setTimeout(() => console.log('2'), 0)

setImmediate(() => console.log('3'))

process.nextTick(() => console.log('4'))

Promise.resolve().then(() => console.log('5'))

// 输出顺序:1 → 4 → 5 → 2 → 3

全局对象 ​

global / globalThis ​

js
// Node.js 全局对象
global.myVar = '全局变量'

// ECMAScript 2020 — 跨环境全局对象
globalThis.myVar = '全局变量'  // Node → global, 浏览器 → window
// Node.js 全局对象
global.myVar = '全局变量'

// ECMAScript 2020 — 跨环境全局对象
globalThis.myVar = '全局变量'  // Node → global, 浏览器 → window

全局 API ​

js
setTimeout(() => {}, 1000)
setInterval(() => {}, 1000)
setImmediate(() => {})  // 当前事件循环 poll 阶段完成后执行
clearTimeout()
clearInterval()
clearImmediate()
setTimeout(() => {}, 1000)
setInterval(() => {}, 1000)
setImmediate(() => {})  // 当前事件循环 poll 阶段完成后执行
clearTimeout()
clearInterval()
clearImmediate()

__dirname / __filename ​

只能在 CommonJS 中使用,ES Module 中不可用:

js
console.log(__dirname)   // 当前模块所在目录的绝对路径
console.log(__filename)  // 当前模块文件的绝对路径(含文件名)
console.log(__dirname)   // 当前模块所在目录的绝对路径
console.log(__filename)  // 当前模块文件的绝对路径(含文件名)

Buffer 类 ​

详见 Node-流与Buffer

process 对象 ​

进程信息 ​

js
process.arch             // CPU 架构:'x64', 'arm64' 等
process.platform         // 操作系统:'win32', 'darwin', 'linux'
process.pid              // 当前进程 ID
process.cwd()            // 当前工作目录
process.memoryUsage()    // 内存使用情况
process.arch             // CPU 架构:'x64', 'arm64' 等
process.platform         // 操作系统:'win32', 'darwin', 'linux'
process.pid              // 当前进程 ID
process.cwd()            // 当前工作目录
process.memoryUsage()    // 内存使用情况
js
console.log(process.memoryUsage())
// {
//   rss: 30932992,      // 常驻集大小(物理内存)
//   heapTotal: 6438912, // V8 堆区总大小
//   heapUsed: 5678624,  // 已用堆大小
//   external: 423221,   // 外部内存(C++ 对象)
//   arrayBuffers: 17606 // ArrayBuffer 数量
// }
console.log(process.memoryUsage())
// {
//   rss: 30932992,      // 常驻集大小(物理内存)
//   heapTotal: 6438912, // V8 堆区总大小
//   heapUsed: 5678624,  // 已用堆大小
//   external: 423221,   // 外部内存(C++ 对象)
//   arrayBuffers: 17606 // ArrayBuffer 数量
// }

命令行参数 ​

js
// 执行:node index.js --name=zs --age=18
console.log(process.argv)
// ['node.exe路径', 'index.js路径', '--name=zs', '--age=18']
// 执行:node index.js --name=zs --age=18
console.log(process.argv)
// ['node.exe路径', 'index.js路径', '--name=zs', '--age=18']

环境变量 ​

js
console.log(process.env.NODE_ENV)  // 读取环境变量
process.env.MY_VAR = 'value'       // 设置(仅当前进程生效)
console.log(process.env.NODE_ENV)  // 读取环境变量
process.env.MY_VAR = 'value'       // 设置(仅当前进程生效)

cross-env ​

跨平台设置环境变量:

json
{
  "scripts": {
    "dev": "cross-env NODE_ENV=development node index.js"
  }
}
{
  "scripts": {
    "dev": "cross-env NODE_ENV=development node index.js"
  }
}

原理:Windows 使用 SET,POSIX 使用 export。

process.exit / process.kill ​

js
process.exit(0)       // 强制退出进程,0 表示正常退出
process.kill(pid)     // 杀死指定进程
process.exit(0)       // 强制退出进程,0 表示正常退出
process.kill(pid)     // 杀死指定进程

process.nextTick ​

将回调插入微任务队列,在当前事件循环下一轮执行:

js
process.nextTick(() => {
  console.log('在当前操作完成后立即执行')
})
process.nextTick(() => {
  console.log('在当前操作完成后立即执行')
})

process.stdout / process.stderr ​

js
process.stdout.write('输出到控制台\n')
process.stderr.write('错误信息\n')
process.stdout.write('输出到控制台\n')
process.stderr.write('错误信息\n')

事件监听 ​

js
process.on('exit', (code) => {
  console.log(`进程退出,退出码:${code}`)
})

process.on('uncaughtException', (err) => {
  console.error('未捕获的异常:', err)
})
process.on('exit', (code) => {
  console.log(`进程退出,退出码:${code}`)
})

process.on('uncaughtException', (err) => {
  console.error('未捕获的异常:', err)
})

child_process 子进程 ​

Node.js 提供了 7 个 API 创建子进程(Sync 结尾为同步方法):

API说明
spawn执行命令,返回流(边执行边返回)
exec执行命令,返回 buffer(最大 200KB)
execFile执行可执行文件
fork创建 Node 子进程(IPC 通信)
execSyncexec 的同步版本
execFileSyncexecFile 的同步版本
spawnSyncspawn 的同步版本

exec ​

js
const { exec, execSync } = require('child_process')

// 异步
exec('node -v', (err, stdout, stderr) => {
  if (err) return console.error(err)
  console.log(stdout.toString())
})

// 同步
const version = execSync('node -v')
console.log(version.toString())
const { exec, execSync } = require('child_process')

// 异步
exec('node -v', (err, stdout, stderr) => {
  if (err) return console.error(err)
  console.log(stdout.toString())
})

// 同步
const version = execSync('node -v')
console.log(version.toString())

execFile ​

适合执行 .bat/.sh 等脚本文件:

js
const { execFile } = require('child_process')

execFile(path.resolve(process.cwd(), './script.bat'), null, (err, stdout) => {
  console.log(stdout.toString())
})
const { execFile } = require('child_process')

execFile(path.resolve(process.cwd(), './script.bat'), null, (err, stdout) => {
  console.log(stdout.toString())
})

spawn ​

适用于实时获取输出数据(流式返回,无大小限制):

js
const { spawn } = require('child_process')

const { stdout } = spawn('netstat', ['-an'], {})

stdout.on('data', (stream) => {
  console.log(stream.toString())
})
const { spawn } = require('child_process')

const { stdout } = spawn('netstat', ['-an'], {})

stdout.on('data', (stream) => {
  console.log(stream.toString())
})

spawn vs exec:

特性spawnexec
返回方式流(stream)buffer
大小限制无200KB
适用场景大数据量、实时输出简单命令、结果较小

fork ​

适用于大量计算或易阻塞主进程的操作(基于 IPC 通信):

js
// index.js
const { fork } = require('child_process')
const child = fork('./child.js')

child.send('我是主进程')  // 发送消息
child.on('message', (data) => {
  console.log('主进程收到:', data)
})
// index.js
const { fork } = require('child_process')
const child = fork('./child.js')

child.send('我是主进程')  // 发送消息
child.on('message', (data) => {
  console.log('主进程收到:', data)
})
js
// child.js
process.on('message', (data) => {
  console.log('子进程收到:', data)
})

process.send('我是子进程')
// child.js
process.on('message', (data) => {
  console.log('子进程收到:', data)
})

process.send('我是子进程')