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 → setImmediatejs
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 → 3console.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 类
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 通信) |
execSync | exec 的同步版本 |
execFileSync | execFile 的同步版本 |
spawnSync | spawn 的同步版本 |
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:
| 特性 | spawn | exec |
|---|---|---|
| 返回方式 | 流(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('我是子进程')
Cao Note