目录
一、Node.js概念
1. Node.js 的用途
2. Node.js 为何能执行 JS 代码?
3. Node.js 与浏览器环境的 JS 最大区别
4. Node.js 如何执行代码?
二、常用核心模块
1. fs模块(文件系统)
2. path模块(路径处理)
3. http模块(HTTP 服务器)
Node.js 是一个基于 Chrome V8 引擎 的 JavaScript 运行时环境,专为服务器端和命令行工具设计。它采用 事件驱动 和 非阻塞 I/O 模型,能够高效处理高并发请求,尤其适合 I/O 密集型应用。
Node.js 主要用于以下场景:
Web 服务器:构建高性能的 HTTP 服务器(如 Express、Fastify)。
API 服务:开发 RESTful API 或 GraphQL 服务。
实时应用:聊天室、在线游戏(结合 WebSocket)。
工具开发:构建 CLI 工具(如 Webpack、Babel)、自动化脚本。
微服务:轻量级服务间的通信(如消息队列、RPC)。
Serverless 函数:部署到 AWS Lambda、Vercel 等无服务器平台。
Node.js 能执行 JavaScript 代码的核心是 V8 引擎:
V8 引擎:Google 开发的 JavaScript 引擎,将 JS 代码直接编译为机器码(而非解释执行),提供高性能。
运行时环境:Node.js 在 V8 基础上扩展了 文件操作、网络通信 等能力,通过内置模块(如 fs
、http
)暴露给开发者。
异步 I/O 支持:依赖 Libuv 库 处理非阻塞操作(如文件读写、网络请求),通过事件循环机制调度任务。
特性 | Node.js | 浏览器 JS |
---|---|---|
全局对象 | global |
window |
API 支持 | 文件系统、进程管理、原生 TCP/UDP | DOM 操作、Web API(如 Fetch) |
模块系统 | CommonJS / ES 模块 | ES 模块(依赖 ) |
代码执行目的 | 服务端、工具链 | 操作页面、响应用户交互 |
安全限制 | 可访问本地文件、执行系统命令 | 受沙箱限制,禁止文件操作 |
依赖管理 | 通过 npm 或 yarn 管理 |
通过 标签或 ES 模块导入 |
Node.js 执行代码的流程如下:
加载 JS 文件:通过 node app.js
启动,读取文件内容。
V8 编译执行:V8 引擎将 JS 代码编译为机器码并执行。
事件循环(Event Loop):
阶段划分:分为 timers
(定时器)、I/O callbacks
(I/O 回调)、idle
(空闲)、poll
(轮询)、check
(setImmediate
)等阶段。
非阻塞 I/O:异步操作(如读取文件)由 Libuv 的线程池处理,完成后回调推入事件队列。
单线程调度:主线程按事件循环阶段顺序处理队列中的回调。
线程池协作:
Libuv 默认创建 4 个线程处理异步 I/O(如文件操作、DNS 解析)。
CPU 密集型任务需手动使用 Worker Threads
或子进程(child_process
)避免阻塞主线程。
作用:操作本地文件系统。
常用方法:
方法名 | 说明 | 同步/异步 |
---|---|---|
fs.readFile(path, [options], callback) |
异步读取文件内容 | 异步 |
fs.readFileSync(path, [options]) |
同步读取文件内容 | 同步 |
fs.writeFile(path, data, [options], callback) |
异步写入文件(覆盖原有内容) | 异步 |
fs.appendFile(path, data, [options], callback) |
异步追加内容到文件末尾 | 异步 |
fs.unlink(path, callback) |
删除文件 | 异步 |
fs.mkdir(path, [options], callback) |
创建目录 | 异步 |
fs.readdir(path, [options], callback) |
读取目录内容 | 异步 |
fs.stat(path, callback) |
获取文件/目录状态信息(如大小、类型) | 异步 |
步骤:
加载 fs 模块,得到 fs 对象
const fs = require('fs')
写入文件内容语法:
fs.writeFile('文件路径', '写入内容', err => {
// 写入后的回调函数
})
读取文件内容的语法
fs.readFile('文件路径', (err, data) => {
// 读取后的回调函数
// data 是文件内容的 Buffer 数据流
})
示例:
// 1. 引入 fs 模块
const fs = require('fs')
// 2. 调用 writeFile 写入内容(覆盖)
fs.writeFile('./test.txt', 'Hello Node.js!', (err) => {
if (err) console.log(err)
else console.log('success')
})
// 3. 调用 readFile 读取内容
fs.readFile('./test.txt', (err, data) => {
if (err) console.log(err)
else console.log(data.toString()) // 把 Buffer 数据流转成字符串类型
})
作用:规范化、拼接、解析文件路径,避免跨平台兼容性问题。
常用方法:
方法名 | 说明 |
---|---|
path.join(...paths) |
拼接路径(自动处理 / 和 \ ) |
path.resolve(...paths) |
解析为绝对路径(从右向左拼接) |
path.dirname(path) |
获取路径的目录部分(如 /a/b/c.js → /a/b ) |
path.basename(path, [ext]) |
获取文件名(可选去除扩展名) |
path.extname(path) |
获取文件扩展名(如 .js ) |
path.parse(path) |
将路径解析为对象(root, dir, base, ext, name) |
要点:在 Node.js 中,相对路径的解析基准始终是当前终端的工作目录(process.cwd()
),而非代码文件所在目录。
示例场景:
假设你的代码文件路径为 D:\project\src\app.js
,若在终端执行 node src/app.js
,则:
process.cwd()
(当前工作目录)是 D:\project\
__dirname
(代码文件所在目录)是 D:\project\src\
所以下面的写法存在风险:
fs.readFile('../node.js/hello.txt', (err, data) => {
if (err) console.log(err)
else console.log(data.toString())
})
巧合正确的原因:
你直接在 D:\practise\ajax\test
目录下执行代码,此时 process.cwd()
是 D:\practise\ajax\test
,于是 ../node.js/hello.txt
被解析为 D:\practise\ajax\node.js\hello.txt
,与 pathStr
结果一致。
风险:
若在父目录(如 ajax
)执行 node test/app.js
,则 ../node.js/hello.txt
会指向 D:\practise\node.js\hello.txt
(错误路径),而 pathStr
仍正确。
解决方案:
使用模块内置变量 __dirname
配合 path.join() 来得到绝对路径使用。
const fs = require('fs')
const path = require('path')
console.log(__dirname) //D:\practise\ajax\test
const pathStr = path.join(__dirname, '..', 'node.js/hello.txt')
console.log(pathStr) //D:\practise\ajax\node.js\hello.txt
fs.readFile('../node.js/hello.txt', (err, data) => {
if (err) console.log(err)
else console.log(data.toString())
})
作用:创建 HTTP 服务器或客户端,处理网络请求。
核心类与方法:
类/方法 | 说明 |
---|---|
http.createServer([options], requestListener) |
创建 HTTP 服务器 |
server.listen(port, [host], [callback]) |
启动服务器监听端口 |
http.request(options, callback) |
发起 HTTP 请求(客户端) |
http.get(options, callback) |
发起 GET 请求(简化版) |
步骤:
引入 http 模块,创建 Web 服务对象
监听 request 请求事件,对本次请求做一些响应处理
启动 Web 服务监听对应端口号
在终端进程中运行本服务,用浏览器发起请求
示例:
// 1.1 加载 http 模块,创建 Web 服务对象
const http = require('http')
const server = http.createServer()
// 1.2 监听 request 请求事件,设置响应头和响应体
server.on('request', (req, res) => {
// 设置响应头-内容类型-普通文本以及中文编码格式
res.setHeader('Content-Type', 'text/plain;charset=utf-8')
// 设置响应体内容,结束本次请求与响应
res.end('欢迎使用 Node.js 和 http 模块创建的 Web 服务')
})
// 1.3 配置端口号并启动 Web 服务
server.listen(8080, () => console.log('服务已启动'))
案例:
编写 web 服务,监听到请求的是 /index.html 时,返回该页面的内容。
const fs = require('fs')
const path = require('path')
const http = require('http')
const server = http.createServer((req, res) => {
// 使用 req.url 获取请求资源路径,并读取 index.html 里字符串内容返回给请求方
if (req.url === '/index.html') {
fs.readFile(path.join(__dirname, 'index.html'), (err, data) => {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(data.toString())
})
} else {
// 其他路径,暂时返回不存在提示
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('资源路径不存在')
}
});
server.listen(8080, () => {
console.log('Server running at http://localhost:8080/');
});
writeHead() 方法: