Node.js 让 JavaScript 走出了浏览器,成为了一门真正的全栈语言。从服务端开发到命令行工具,Node.js 的应用场景极其广泛。
Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时环境。
| 特性 | 说明 | 优势 |
|---|---|---|
| 事件驱动 | 基于事件循环模型 | 高并发处理能力 |
| 非阻塞 I/O | 异步操作不阻塞主线程 | 适合 I/O 密集型应用 |
| 单线程 | 主线程单线程执行 | 无锁竞争,简单可靠 |
| 跨平台 | 支持 Windows、Linux、macOS | 一次编写,到处运行 |
| NPM 生态 | 世界上最大的包管理器 | 海量开源资源 |
// 浏览器环境
console.log(window); // 全局对象
console.log(document); // DOM 操作
console.log(alert); // 用户交互
// Node.js 环境
console.log(global); // 全局对象
console.log(process); // 进程信息
console.log(Buffer); // 二进制数据处理
💡 东巴文提示:Node.js 和浏览器都是 JavaScript 的运行环境,但它们提供的 API 不同。浏览器专注于页面交互,Node.js 专注于系统操作。
# 使用 nvm 安装(推荐)
nvm install --lts # 安装 LTS 版本
nvm use --lts # 使用 LTS 版本
nvm ls # 查看已安装版本
# 验证安装
node -v # 查看 Node.js 版本
npm -v # 查看 npm 版本
| 版本类型 | 说明 | 适用场景 |
|---|---|---|
| LTS(长期支持版) | 稳定,维护周期长 | 生产环境 |
| Current(当前版) | 最新特性,更新频繁 | 开发测试 |
| 奇数版本 | 实验性功能 | 尝鲜体验 |
REPL(Read-Eval-Print-Loop)是 Node.js 的交互式解释器。
// 启动 REPL
// $ node
// 基本运算
> 1 + 1
2
// 变量定义
> const name = '东巴文'
undefined
> name
'东巴文'
// 多行输入
> function add(a, b) {
... return a + b
... }
undefined
> add(1, 2)
3
// 特殊命令
> .help // 显示帮助
> .exit // 退出 REPL
> .clear // 清除上下文
Node.js 采用 CommonJS 模块规范。
// 方式一:exports 对象
// math.js
exports.add = function(a, b) {
return a + b
}
exports.subtract = function(a, b) {
return a - b
}
exports.PI = 3.14159
// 方式二:module.exports
// calculator.js
class Calculator {
add(a, b) { return a + b }
subtract(a, b) { return a - b }
multiply(a, b) { return a * b }
divide(a, b) { return a / b }
}
module.exports = Calculator
// 也可以导出对象
module.exports = {
name: '东巴文计算器',
version: '1.0.0',
Calculator
}
// 导入核心模块
const fs = require('fs')
const path = require('path')
const http = require('http')
// 导入自定义模块
const math = require('./math')
const Calculator = require('./calculator')
// 使用导入的模块
console.log(math.add(1, 2)) // 3
console.log(math.PI) // 3.14159
const calc = new Calculator()
console.log(calc.multiply(3, 4)) // 12
// 解构导入
const { add, subtract, PI } = require('./math')
// 模块查找顺序
require('./utils') // 1. 查找相对路径
require('lodash') // 2. 查找 node_modules
require('fs') // 3. 查找核心模块
// 查找 node_modules 的顺序
// 项目/node_modules/lodash
// 项目/node_modules/../node_modules/lodash
// ...直到根目录
// 全局 node_modules
const fs = require('fs')
const path = require('path')
// 同步读取
const data = fs.readFileSync('./file.txt', 'utf-8')
console.log(data)
// 异步读取(回调)
fs.readFile('./file.txt', 'utf-8', (err, data) => {
if (err) throw err
console.log(data)
})
// Promise 版本
const fsPromises = require('fs').promises
async function readFile() {
try {
const data = await fsPromises.readFile('./file.txt', 'utf-8')
console.log(data)
} catch (err) {
console.error('读取失败:', err)
}
}
// 写入文件
fs.writeFileSync('./output.txt', '东巴文内容')
// 追加内容
fs.appendFileSync('./output.txt', '\n新增行')
// 检查文件是否存在
fs.existsSync('./file.txt')
// 获取文件信息
const stats = fs.statSync('./file.txt')
console.log(stats.isFile()) // 是否是文件
console.log(stats.isDirectory()) // 是否是目录
console.log(stats.size) // 文件大小
// 创建目录
fs.mkdirSync('./new-dir', { recursive: true })
// 读取目录
const files = fs.readdirSync('./')
console.log(files)
// 删除文件
fs.unlinkSync('./file.txt')
// 删除目录
fs.rmdirSync('./empty-dir')
const path = require('path')
// 路径拼接
const fullPath = path.join('/home', 'user', 'documents', 'file.txt')
console.log(fullPath) // /home/user/documents/file.txt
// 获取文件名
console.log(path.basename('/home/user/file.txt')) // file.txt
console.log(path.basename('/home/user/file.txt', '.txt')) // file
// 获取目录名
console.log(path.dirname('/home/user/file.txt')) // /home/user
// 获取扩展名
console.log(path.extname('file.txt')) // .txt
console.log(path.extname('file.tar.gz')) // .gz
// 解析路径
const parsed = path.parse('/home/user/file.txt')
console.log(parsed)
// {
// root: '/',
// dir: '/home/user',
// base: 'file.txt',
// ext: '.txt',
// name: 'file'
// }
// 绝对路径
console.log(path.resolve('./file.txt'))
console.log(path.resolve('/home', 'user', 'file.txt'))
// 规范化路径
console.log(path.normalize('/home/../user/./file.txt')) // /user/file.txt
// 相对路径
console.log(path.relative('/home/user', '/home/admin')) // ../admin
// 当前工作目录
console.log(process.cwd())
// __dirname 和 __filename
console.log(__dirname) // 当前文件所在目录
console.log(__filename) // 当前文件完整路径
const http = require('http')
// 创建服务器
const server = http.createServer((req, res) => {
// 请求信息
console.log(req.method) // 请求方法
console.log(req.url) // 请求路径
console.log(req.headers) // 请求头
// 设置响应头
res.writeHead(200, {
'Content-Type': 'text/html; charset=utf-8'
})
// 发送响应
res.end('<h1>东巴文欢迎你</h1>')
})
// 监听端口
server.listen(3000, () => {
console.log('服务器运行在 http://localhost:3000')
})
// 处理不同的路由
const server2 = http.createServer((req, res) => {
const url = new URL(req.url, `http://${req.headers.host}`)
res.writeHead(200, { 'Content-Type': 'application/json' })
if (url.pathname === '/') {
res.end(JSON.stringify({ message: '首页' }))
} else if (url.pathname === '/api/users') {
res.end(JSON.stringify({ users: ['东巴文', '用户A', '用户B'] }))
} else if (url.pathname === '/api/query') {
const name = url.searchParams.get('name')
res.end(JSON.stringify({ name }))
} else {
res.writeHead(404)
res.end(JSON.stringify({ error: '未找到' }))
}
})
server2.listen(3001)
const EventEmitter = require('events')
// 创建事件发射器
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter()
// 监听事件
myEmitter.on('event', (data) => {
console.log('事件触发:', data)
})
// 只监听一次
myEmitter.once('once', () => {
console.log('只执行一次')
})
// 触发事件
myEmitter.emit('event', '东巴文数据')
myEmitter.emit('once')
myEmitter.emit('once') // 不会再次触发
// 移除监听
const callback = () => console.log('回调')
myEmitter.on('test', callback)
myEmitter.off('test', callback)
// 获取监听器数量
console.log(myEmitter.listenerCount('event'))
// 进程信息
console.log(process.pid) // 进程 ID
console.log(process.ppid) // 父进程 ID
console.log(process.platform) // 操作系统平台
console.log(process.arch) // CPU 架构
console.log(process.version) // Node.js 版本
console.log(process.versions) // 各组件版本
// 环境变量
console.log(process.env) // 所有环境变量
console.log(process.env.NODE_ENV) // NODE_ENV
console.log(process.env.PATH) // PATH
// 设置环境变量
process.env.MY_VAR = '东巴文'
// 命令行参数
console.log(process.argv)
// ['node路径', '脚本路径', '参数1', '参数2']
// 解析参数
const args = process.argv.slice(2)
console.log(args)
// 当前工作目录
console.log(process.cwd())
// 退出进程
process.exit(0) // 正常退出
process.exit(1) // 异常退出
// 退出钩子
process.on('exit', (code) => {
console.log('进程退出,代码:', code)
})
// 未捕获异常
process.on('uncaughtException', (err) => {
console.error('未捕获异常:', err)
process.exit(1)
})
// 未处理的 Promise 拒绝
process.on('unhandledRejection', (reason, promise) => {
console.error('未处理的拒绝:', reason)
})
// 内存使用
console.log(process.memoryUsage())
// {
// rss: 常驻内存,
// heapTotal: 堆总量,
// heapUsed: 堆使用量,
// external: 外部内存
// }
// 下一个事件循环
process.nextTick(() => {
console.log('下一个 tick')
})
// 创建 Buffer
const buf1 = Buffer.alloc(10) // 分配 10 字节,填充 0
const buf2 = Buffer.allocUnsafe(10) // 分配 10 字节,不初始化
const buf3 = Buffer.from('东巴文') // 从字符串创建
const buf4 = Buffer.from([1, 2, 3]) // 从数组创建
// 写入数据
buf1.write('Hello')
console.log(buf1.toString()) // Hello
// 读取数据
console.log(buf3.toString()) // 东巴文
console.log(buf3.toString('utf-8'))
// Buffer 操作
const buf5 = Buffer.from('Hello ')
const buf6 = Buffer.from('World')
const buf7 = Buffer.concat([buf5, buf6])
console.log(buf7.toString()) // Hello World
// Buffer 比较
console.log(buf5.equals(buf6)) // false
console.log(buf5.compare(buf6)) // -1(buf5 < buf6)
// Buffer 切片
const buf8 = Buffer.from('东巴文教程')
console.log(buf8.slice(0, 9).toString()) // 东巴文
// Buffer 长度
console.log(buf3.length) // 字节长度
console.log(Buffer.byteLength('东巴文')) // 9
// Buffer 与 JSON
const json = JSON.stringify(buf3)
console.log(json) // {"type":"Buffer","data":[...]}
console.log(Buffer.from(JSON.parse(json)))
const fs = require('fs')
const { Readable, Writable, Transform, pipeline } = require('stream')
// 可读流
const readStream = fs.createReadStream('./large-file.txt', {
encoding: 'utf-8',
highWaterMark: 64 * 1024 // 64KB 缓冲区
})
readStream.on('data', (chunk) => {
console.log('读取到数据:', chunk.length)
})
readStream.on('end', () => {
console.log('读取完成')
})
readStream.on('error', (err) => {
console.error('读取错误:', err)
})
// 可写流
const writeStream = fs.createWriteStream('./output.txt')
writeStream.write('第一行\n')
writeStream.write('第二行\n')
writeStream.end() // 结束写入
writeStream.on('finish', () => {
console.log('写入完成')
})
// 管道操作
const readStream2 = fs.createReadStream('./input.txt')
const writeStream2 = fs.createWriteStream('./output.txt')
readStream2.pipe(writeStream2)
// 转换流
const upperCase = new Transform({
transform(chunk, encoding, callback) {
this.push(chunk.toString().toUpperCase())
callback()
}
})
// 链式管道
fs.createReadStream('./input.txt')
.pipe(upperCase)
.pipe(fs.createWriteStream('./output-upper.txt'))
// pipeline(推荐)
pipeline(
fs.createReadStream('./input.txt'),
upperCase,
fs.createWriteStream('./output.txt'),
(err) => {
if (err) {
console.error('管道错误:', err)
} else {
console.log('管道完成')
}
}
)
// 自定义可读流
class MyReadable extends Readable {
constructor(options) {
super(options)
this.data = ['东', '巴', '文']
this.index = 0
}
_read(size) {
if (this.index < this.data.length) {
this.push(this.data[this.index])
this.index++
} else {
this.push(null) // 结束
}
}
}
const myReadable = new MyReadable()
myReadable.on('data', (chunk) => {
console.log(chunk.toString())
})
#!/usr/bin/env node
// cli.js
const fs = require('fs')
const path = require('path')
// 解析命令行参数
const args = process.argv.slice(2)
const command = args[0]
const params = args.slice(1)
// 帮助信息
function showHelp() {
console.log(`
东巴文 CLI 工具
用法:
node cli.js <command> [options]
命令:
init <name> 创建新项目
list 列出当前目录文件
read <file> 读取文件内容
help 显示帮助信息
`)
}
// 创建项目
function initProject(name) {
const dir = path.join(process.cwd(), name)
if (fs.existsSync(dir)) {
console.log(`目录 ${name} 已存在`)
return
}
fs.mkdirSync(dir)
fs.mkdirSync(path.join(dir, 'src'))
const packageJson = {
name,
version: '1.0.0',
main: 'src/index.js'
}
fs.writeFileSync(
path.join(dir, 'package.json'),
JSON.stringify(packageJson, null, 2)
)
fs.writeFileSync(
path.join(dir, 'src', 'index.js'),
`console.log('东巴文 ${name}')`
)
console.log(`项目 ${name} 创建成功`)
}
// 列出文件
function listFiles() {
const files = fs.readdirSync(process.cwd())
files.forEach(file => {
const stats = fs.statSync(file)
const type = stats.isDirectory() ? '📁' : '📄'
console.log(`${type} ${file}`)
})
}
// 读取文件
function readFile(filename) {
const filepath = path.join(process.cwd(), filename)
if (!fs.existsSync(filepath)) {
console.log(`文件 ${filename} 不存在`)
return
}
const content = fs.readFileSync(filepath, 'utf-8')
console.log(content)
}
// 命令分发
switch (command) {
case 'init':
initProject(params[0])
break
case 'list':
listFiles()
break
case 'read':
readFile(params[0])
break
case 'help':
default:
showHelp()
}
{
"name": "dongba-project",
"version": "1.0.0",
"description": "东巴文项目",
"main": "src/index.js",
"scripts": {
"start": "node src/index.js",
"dev": "nodemon src/index.js",
"test": "jest"
},
"keywords": ["javascript", "nodejs"],
"author": "东巴文",
"license": "MIT",
"dependencies": {
"express": "^4.18.0"
},
"devDependencies": {
"nodemon": "^3.0.0",
"jest": "^29.0.0"
},
"engines": {
"node": ">=18.0.0"
},
"type": "module"
}
Node.js 入门后,你可以继续学习:
东巴文(db-w.cn)—— 让 Node.js 开发更简单