nodejs开发重点
以下是 Node.js 核心知识重点的详细整理,涵盖基础概念、异步编程、核心模块、工程化等关键领域,构建系统的知识体系:
项目实践
code/all/e-ysy electron
code/all/e-ipub electron
code/all/cloud-api-gateway koa koa-router
code/all/nodejs-html2pdf koa puppeteer
…
一、Node.js 基础与核心特性
- 定义:基于 Chrome V8 引擎的 JavaScript 运行时,采用事件驱动、非阻塞 I/O 模型,适合构建高性能网络应用。
- 核心优势:
- 单线程(主线程)+ 事件循环,避免多线程开销;
- 非阻塞 I/O 使异步操作高效处理并发请求;
- 跨平台(Windows/Linux/macOS),npm 生态丰富。
二、异步编程模型
Node.js 的核心灵魂,解决单线程下的并发问题。
1. 异步方式演进
- 回调函数:早期方案,易导致“回调地狱”(Callback Hell)。
1
2
3
4fs.readFile('file.txt', (err, data) => {
if (err) throw err;
// 嵌套回调...
}); - Promise:链式调用,解决回调嵌套。
1
2
3
4const readFile = (path) => new Promise((resolve, reject) => {
fs.readFile(path, (err, data) => err ? reject(err) : resolve(data));
});
readFile('file.txt').then(data => ...).catch(err => ...); - async/await:语法糖,让异步代码看起来同步。
1
2
3
4
5
6
7async function fetchData() {
try {
const data = await readFile('file.txt');
} catch (err) {
console.error(err);
}
}
2. 事件循环机制(Event Loop)
Node.js 异步的核心,分6个阶段循环执行:
- Timers:执行
setTimeout/setInterval回调; - Pending Callbacks:执行系统操作(如 TCP 错误)的回调;
- Idle/Prepare:内部使用;
- Poll:获取新 I/O 事件,阻塞或执行回调;
- Check:执行
setImmediate回调; - Close Callbacks:执行
socket.on('close', ...)等关闭回调。
宏任务 vs 微任务:
- 宏任务:
setTimeout/setInterval/setImmediate/I/O; - 微任务:
process.nextTick/Promise.then/catch/finally/queueMicrotask; - 执行顺序:微任务优先于宏任务,每个宏任务执行完清空微任务队列。
三、核心模块
Node.js 内置常用模块,无需安装即可使用。
1. 文件系统(fs)
- 同步/异步读写:
fs.readFile(异步)、fs.readFileSync(同步); - 流式操作:
fs.createReadStream/fs.createWriteStream(处理大文件); - 路径处理:配合
path模块避免跨平台问题。
2. 网络(http/https)
- 创建服务器:
1
2
3
4
5
6const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello World');
});
server.listen(3000); - 发起请求:
http.get/http.request。
3. 路径(path)
- 常用方法:
path.join(拼接路径)、path.resolve(解析绝对路径)、path.extname(获取扩展名)。
4. 事件(events)
- 发布-订阅模式,通过
EventEmitter实现:1
2
3
4const { EventEmitter } = require('events');
const emitter = new EventEmitter();
emitter.on('event', (msg) => console.log(msg)); // 监听
emitter.emit('event', 'Hello'); // 触发
5. 进程(process)
- 环境变量:
process.env; - 退出:
process.exit(); - 标准输入输出:
process.stdin/process.stdout。
四、模块系统
1. CommonJS 规范
- 导入:
require('模块路径'); - 导出:
module.exports(推荐)或exports(注意:exports是module.exports的引用,直接赋值会断开引用); - 缓存:模块首次加载后会被缓存,多次
require返回同一实例。
2. ES Modules(ESM)
- Node.js 12+ 支持,需在
package.json中设置"type": "module"或使用.mjs后缀; - 语法:
import/export。
五、流(Stream)与背压
1. 流的类型
- 可读流(Readable):如
fs.createReadStream; - 可写流(Writable):如
fs.createWriteStream; - 双工流(Duplex):同时可读可写;
- 转换流(Transform):读写过程中可修改数据(如
zlib.createGzip)。
2. 背压(Backpressure)
- 问题:可读流速度 > 可写流速度时,数据积压;
- 解决:使用
pipe()自动处理背压,或手动监听drain事件。
六、错误处理
- 错误优先回调:回调函数第一个参数为 error。
- Promise 错误:通过
.catch()捕获。 - async/await 错误:使用
try/catch。 - 全局错误捕获:
process.on('uncaughtException', (err) => { ... })(同步错误);process.on('unhandledRejection', (reason, promise) => { ... })(未处理的 Promise 错误)。
七、性能优化与集群
- 多核利用(cluster 模块):
1
2
3
4
5
6
7const cluster = require('cluster');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
for (let i = 0; i < numCPUs; i++) cluster.fork();
} else {
// 子进程启动服务器
} - 内存管理:避免内存泄漏(如未关闭的文件描述符、全局变量),使用
heapdump等工具排查。 - 缓存:使用 Redis 等缓存热点数据,减少数据库查询。
八、工具链与工程化
- 包管理:npm/yarn/pnpm,常用命令:
npm init/npm install/npm run。 - 进程管理:
nodemon:开发时自动重启;pm2:生产环境进程守护、负载均衡。
- 构建工具:Webpack/Rollup/esbuild(打包代码)。
九、Web 开发与中间件
- Express:轻量级 Web 框架,核心是中间件机制:
- 应用级中间件:
app.use((req, res, next) => { ... }); - 路由级中间件:
express.Router(); - 错误处理中间件:
(err, req, res, next) => { ... }。
- 应用级中间件:
- Koa:更轻量,使用 async/await 中间件,“洋葱模型”执行顺序。
十、安全最佳实践
- 输入验证:使用 Joi/express-validator 等库验证用户输入;
- 安全头:使用
helmet中间件设置 XSS、CSP 等安全头; - 防止 SQL 注入:使用参数化查询(如 mysql2 的
?占位符); - 依赖安全:定期运行
npm audit检查漏洞。
十一、调试与测试
- 调试:使用
node --inspect配合 Chrome DevTools,或 VS Code 调试; - 测试:Jest/Mocha(单元测试)、Supertest(接口测试)。
以下是针对 Electron 桌面开发、Koa Web 开发 和 Express Web 开发 三个场景,Node.js 知识重点的详细整理:
一、Electron 开发中的 Node.js 重点
Electron 结合了 Chromium 和 Node.js,让你用 Web 技术开发桌面应用。Node.js 在 Electron 中主要负责系统级能力和进程通信。
1. 进程模型(核心基础)
- 主进程(Main Process):
- 只有一个,负责创建窗口、管理应用生命周期(
app模块)。 - 完整拥有 Node.js 所有 API(如
fs、path、child_process)。
- 只有一个,负责创建窗口、管理应用生命周期(
- 渲染进程(Renderer Process):
- 每个窗口一个,负责渲染 UI(类似浏览器环境)。
- 默认不启用 Node.js 集成(安全考虑),需通过
preload脚本桥接。
- 预加载脚本(Preload Script):
- 运行在渲染进程,但能访问 Node.js API,通过
contextBridge向渲染层暴露安全接口。1
2
3
4
5
6// preload.js 示例
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electronAPI', {
sendMsg: (msg) => ipcRenderer.send('toMain', msg),
onReply: (callback) => ipcRenderer.on('fromMain', (e, data) => callback(data))
});
- 运行在渲染进程,但能访问 Node.js API,通过
2. 进程间通信(IPC)
- 单向通信:
- 渲染→主:
ipcRenderer.send+ipcMain.on - 主→渲染:
webContents.send+ipcRenderer.on
- 渲染→主:
- 双向通信:
ipcRenderer.invoke+ipcMain.handle(推荐,基于 Promise)1
2
3
4
5
6// 主进程
ipcMain.handle('readFile', async (e, path) => {
return await fs.promises.readFile(path, 'utf8');
});
// 渲染进程(通过 preload)
const content = await window.electronAPI.readFile('./test.txt');
3. Node.js 原生模块与系统能力
- 文件系统:用
fs读写本地文件(注意路径处理用path.join/path.resolve)。 - 子进程:
child_process.spawn/exec调用系统命令(如启动外部程序)。 - 原生模块:若使用
node-gyp编译的原生模块,需确保与 Electron 版本匹配(用electron-rebuild重编译)。
4. 安全最佳实践
- **禁用
nodeIntegration**:渲染进程默认不开启 Node.js,通过preload+contextBridge暴露能力。 - **启用
contextIsolation**:隔离渲染进程和 preload 上下文,防止原型链污染。 - 验证 IPC 消息:主进程接收消息时校验来源,避免恶意渲染进程发送非法指令。
二、Koa 开发中的 Node.js 重点
Koa 是轻量级 Web 框架,核心是洋葱模型中间件,极度依赖 Node.js 的 async/await。
1. 洋葱模型中间件机制(核心)
- 中间件通过
app.use()注册,执行顺序像“洋葱圈”:1
2
3
4
5
6
7
8
9
10
11app.use(async (ctx, next) => {
console.log('1 进入');
await next(); // 等待下一个中间件执行完
console.log('1 返回');
});
app.use(async (ctx, next) => {
console.log('2 进入');
ctx.body = 'Hello Koa'; // 设置响应体
console.log('2 返回');
});
// 输出:1 进入 → 2 进入 → 2 返回 → 1 返回 - 必须调用
await next()才能进入下一个中间件,否则请求会被“卡住”。
2. Context(ctx)对象
- Koa 将 Node.js 的
req和res封装到ctx中,提供更便捷的 API:ctx.request/ctx.response:Koa 封装的请求/响应对象。ctx.req/ctx.res:Node.js 原生的请求/响应对象(尽量避免直接用)。- 常用属性:
ctx.method、ctx.path、ctx.query、ctx.body、ctx.status。
3. 路由与中间件生态
- 路由:Koa 本身不带路由,需配合
koa-router:1
2
3
4
5
6const Router = require('koa-router');
const router = new Router();
router.get('/user/:id', async (ctx) => {
ctx.body = { id: ctx.params.id };
});
app.use(router.routes()).use(router.allowedMethods()); - 常用中间件:
koa-bodyparser:解析 POST 请求体(JSON/Form)。koa-static:托管静态文件。koa-views:模板渲染(如 Nunjucks、EJS)。
4. 错误处理
- 中间件捕获:用
try/catch包裹await next():1
2
3
4
5
6
7
8app.use(async (ctx, next) => {
try {
await next();
} catch (err) {
ctx.status = err.status || 500;
ctx.body = { error: err.message };
}
}); - 全局错误监听:
app.on('error', (err, ctx) => { ... })。
5. 异步流程控制
- 充分利用 Node.js 的
async/await处理数据库、文件等异步操作,避免回调地狱。 - 注意:中间件必须返回 Promise(
async函数默认返回 Promise)。
三、Express 开发中的 Node.js 重点
Express 是最成熟的 Node.js Web 框架,生态丰富,核心是中间件系统和路由管理。
1. 中间件系统(核心)
- 中间件分类:
- 应用级中间件:
app.use((req, res, next) => { ... }) - 路由级中间件:
router.use((req, res, next) => { ... }) - 错误处理中间件:
(err, req, res, next) => { ... }(必须 4 个参数) - 内置中间件:
express.static、express.json、express.urlencoded
- 应用级中间件:
- 执行顺序:按代码顺序依次执行,调用
next()进入下一个,不调用则请求终止。
2. 路由管理
- 基础路由:
1
2
3app.get('/user/:id', (req, res) => {
res.send({ id: req.params.id, query: req.query });
}); - 模块化路由(
express.Router):1
2
3
4
5
6
7
8// routes/user.js
const router = express.Router();
router.get('/', (req, res) => res.send('用户列表'));
module.exports = router;
// app.js
const userRouter = require('./routes/user');
app.use('/users', userRouter); // 访问 /users 时匹配该路由
3. 请求与响应对象
- Request(req):
req.params:路由参数(如/user/:id)。req.query:URL 查询参数(如?name=test)。req.body:POST 请求体(需express.json()中间件)。
- Response(res):
res.send():发送响应(自动判断 Content-Type)。res.json():发送 JSON 响应。res.status(404).send('Not Found'):设置状态码。res.sendFile():发送文件。
4. 模板引擎与静态文件
- 模板引擎:支持 EJS、Pug 等,通过
app.set('view engine', 'ejs')设置,用res.render('index', { data })渲染。 - 静态文件:
app.use(express.static('public'))托管 public 目录下的文件(如 CSS、JS、图片)。
5. 生态与最佳实践
- 常用中间件:
cors:解决跨域问题。helmet:安全头设置(防 XSS、点击劫持等)。morgan:日志记录。express-validator:数据校验。
- 错误处理:
1
2
3
4
5
6
7
8
9// 404 处理
app.use((req, res, next) => {
res.status(404).send('页面未找到');
});
// 全局错误处理
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('服务器错误');
});
总结对比
| 场景 | Node.js 核心侧重点 | 关键能力 |
|---|---|---|
| Electron | 进程模型、IPC、系统 API(fs/child_process) | 桌面原生能力、进程通信、安全隔离 |
| Koa | 洋葱模型中间件、async/await、Context | 轻量异步控制、灵活中间件组合 |
| Express | 中间件系统、路由管理、丰富生态 | 快速开发、成熟方案、企业级应用 |
Koa和Express中间件执行对比
结论先行:Express 不是严格意义上的“洋葱模型”,它的中间件执行机制是线性顺序执行**,和 Koa 的“洋葱模型”有本质区别。
一、核心区别对比
| 对比维度 | Koa(洋葱模型) | Express(线性模型) |
|---|---|---|
| 执行流程 | 双向执行:中间件先从外到内“穿透”,执行 next() 前的前置逻辑;然后再从内到外“回溯”,执行 next() 后的后置逻辑,形成完整的洋葱圈。 |
单向执行:中间件按注册顺序线性执行,调用 next() 后直接把控制权交给下一个中间件,不会自动回溯,除非显式在 next() 后写代码(但机制和洋葱模型不同)。 |
| 异步处理 | 基于 async/await,next() 返回 Promise,异步代码天然支持“等待内层执行完再执行外层后置逻辑”,时序控制极其优雅。 |
基于回调函数,next() 是同步的,异步代码需要手动处理回调或 Promise,否则无法保证“内层异步执行完再执行外层后置逻辑”,容易出现时序混乱。 |
| 核心特性 | 每个中间件都有两次处理请求的机会(前置拦截 + 后置处理),非常适合做日志、性能监控、错误捕获、响应包装等切面逻辑。 | 每个中间件通常只有一次处理请求的机会(前置处理),更适合做简单的请求拦截、参数校验、路由分发。 |
二、代码示例直观对比(秒懂差异)
1. Koa 洋葱模型执行示例
1 | |
执行顺序(完美的洋葱圈):
1 | |
2. Express 线性模型执行示例
1 | |
执行顺序(线性顺序,无洋葱回溯):
1 | |
注意:虽然这个同步示例看起来输出顺序和 Koa 一样,但核心差异在异步场景,见下文。
三、异步场景下的本质差异(这才是关键)
Koa 异步场景(天然支持等待)
1 | |
Koa 输出(时序完美):
1 | |
Express 异步场景(时序混乱,需手动处理)
1 | |
Express 输出(时序混乱):
1 | |
Express 要实现 Koa 那样的异步等待,需要手动把 next() 包装成 Promise 并 await,代码会非常冗余,这也是 Koa 洋葱模型的核心优势。
四、总结
- Koa:是真正的洋葱模型,基于
async/await实现优雅的双向执行,每个中间件都能清晰地控制“请求进来时”和“响应出去时”的逻辑,异步处理极其丝滑,适合做复杂的切面逻辑(如全链路日志、性能埋点、统一错误处理、响应格式包装)。 - Express:是线性顺序执行模型,中间件单向流转,虽然可以通过在
next()后写代码模拟部分后置逻辑,但异步时序控制困难,不是真正的洋葱模型,更适合做简单的请求处理和路由分发。