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 基础与核心特性

  1. 定义:基于 Chrome V8 引擎的 JavaScript 运行时,采用事件驱动、非阻塞 I/O 模型,适合构建高性能网络应用。
  2. 核心优势
    • 单线程(主线程)+ 事件循环,避免多线程开销;
    • 非阻塞 I/O 使异步操作高效处理并发请求;
    • 跨平台(Windows/Linux/macOS),npm 生态丰富。

二、异步编程模型

Node.js 的核心灵魂,解决单线程下的并发问题。

1. 异步方式演进

  • 回调函数:早期方案,易导致“回调地狱”(Callback Hell)。
    1
    2
    3
    4
    fs.readFile('file.txt', (err, data) => {
    if (err) throw err;
    // 嵌套回调...
    });
  • Promise:链式调用,解决回调嵌套。
    1
    2
    3
    4
    const 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
    7
    async function fetchData() {
    try {
    const data = await readFile('file.txt');
    } catch (err) {
    console.error(err);
    }
    }

2. 事件循环机制(Event Loop)

Node.js 异步的核心,分6个阶段循环执行:

  1. Timers:执行 setTimeout/setInterval 回调;
  2. Pending Callbacks:执行系统操作(如 TCP 错误)的回调;
  3. Idle/Prepare:内部使用;
  4. Poll:获取新 I/O 事件,阻塞或执行回调;
  5. Check:执行 setImmediate 回调;
  6. 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
    6
    const 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
    4
    const { 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(注意:exportsmodule.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 事件。

六、错误处理

  1. 错误优先回调:回调函数第一个参数为 error。
  2. Promise 错误:通过 .catch() 捕获。
  3. async/await 错误:使用 try/catch
  4. 全局错误捕获
    • process.on('uncaughtException', (err) => { ... })(同步错误);
    • process.on('unhandledRejection', (reason, promise) => { ... })(未处理的 Promise 错误)。

七、性能优化与集群

  1. 多核利用(cluster 模块)
    1
    2
    3
    4
    5
    6
    7
    const cluster = require('cluster');
    const numCPUs = require('os').cpus().length;
    if (cluster.isMaster) {
    for (let i = 0; i < numCPUs; i++) cluster.fork();
    } else {
    // 子进程启动服务器
    }
  2. 内存管理:避免内存泄漏(如未关闭的文件描述符、全局变量),使用 heapdump 等工具排查。
  3. 缓存:使用 Redis 等缓存热点数据,减少数据库查询。

八、工具链与工程化

  1. 包管理:npm/yarn/pnpm,常用命令:npm init/npm install/npm run
  2. 进程管理
    • nodemon:开发时自动重启;
    • pm2:生产环境进程守护、负载均衡。
  3. 构建工具:Webpack/Rollup/esbuild(打包代码)。

九、Web 开发与中间件

  1. Express:轻量级 Web 框架,核心是中间件机制:
    • 应用级中间件:app.use((req, res, next) => { ... })
    • 路由级中间件:express.Router()
    • 错误处理中间件:(err, req, res, next) => { ... }
  2. Koa:更轻量,使用 async/await 中间件,“洋葱模型”执行顺序。

十、安全最佳实践

  1. 输入验证:使用 Joi/express-validator 等库验证用户输入;
  2. 安全头:使用 helmet 中间件设置 XSS、CSP 等安全头;
  3. 防止 SQL 注入:使用参数化查询(如 mysql2 的 ? 占位符);
  4. 依赖安全:定期运行 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(如 fspathchild_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))
      });

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
    11
    app.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 的 reqres 封装到 ctx 中,提供更便捷的 API:
    • ctx.request/ctx.response:Koa 封装的请求/响应对象。
    • ctx.req/ctx.res:Node.js 原生的请求/响应对象(尽量避免直接用)。
    • 常用属性:ctx.methodctx.pathctx.queryctx.bodyctx.status

3. 路由与中间件生态

  • 路由:Koa 本身不带路由,需配合 koa-router
    1
    2
    3
    4
    5
    6
    const 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
    8
    app.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.staticexpress.jsonexpress.urlencoded
  • 执行顺序:按代码顺序依次执行,调用 next() 进入下一个,不调用则请求终止。

2. 路由管理

  • 基础路由:
    1
    2
    3
    app.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/awaitnext() 返回 Promise,异步代码天然支持“等待内层执行完再执行外层后置逻辑”,时序控制极其优雅。 基于回调函数,next() 是同步的,异步代码需要手动处理回调或 Promise,否则无法保证“内层异步执行完再执行外层后置逻辑”,容易出现时序混乱。
核心特性 每个中间件都有两次处理请求的机会(前置拦截 + 后置处理),非常适合做日志、性能监控、错误捕获、响应包装等切面逻辑。 每个中间件通常只有一次处理请求的机会(前置处理),更适合做简单的请求拦截、参数校验、路由分发。

二、代码示例直观对比(秒懂差异)

1. Koa 洋葱模型执行示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const Koa = require('koa');
const app = new Koa();

// 中间件1:最外层
app.use(async (ctx, next) => {
console.log('1-进入外层(前置逻辑)');
await next(); // 等待内层所有中间件执行完
console.log('1-离开外层(后置逻辑)');
});

// 中间件2:中间层
app.use(async (ctx, next) => {
console.log('2-进入中间层(前置逻辑)');
await next();
console.log('2-离开中间层(后置逻辑)');
});

// 中间件3:最内层(实际处理请求)
app.use(async (ctx) => {
console.log('3-处理核心业务逻辑');
ctx.body = 'Hello Koa';
});

app.listen(3000);

执行顺序(完美的洋葱圈)

1
2
3
4
5
1-进入外层(前置逻辑)
2-进入中间层(前置逻辑)
3-处理核心业务逻辑
2-离开中间层(后置逻辑)
1-离开外层(后置逻辑)

2. Express 线性模型执行示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const express = require('express');
const app = express();

// 中间件1:最外层
app.use((req, res, next) => {
console.log('1-进入外层(前置逻辑)');
next(); // 直接交给下一个中间件,不会自动等待
console.log('1-离开外层(后置逻辑)'); // 虽然写了,但执行时机和Koa不同
});

// 中间件2:中间层
app.use((req, res, next) => {
console.log('2-进入中间层(前置逻辑)');
next();
console.log('2-离开中间层(后置逻辑)');
});

// 中间件3:最内层(实际处理请求)
app.use((req, res) => {
console.log('3-处理核心业务逻辑');
res.send('Hello Express');
});

app.listen(3000);

执行顺序(线性顺序,无洋葱回溯)

1
2
3
4
5
1-进入外层(前置逻辑)
2-进入中间层(前置逻辑)
3-处理核心业务逻辑
2-离开中间层(后置逻辑)
1-离开外层(后置逻辑)

注意:虽然这个同步示例看起来输出顺序和 Koa 一样,但核心差异在异步场景,见下文。


三、异步场景下的本质差异(这才是关键)

Koa 异步场景(天然支持等待)

1
2
3
4
5
6
7
8
9
10
11
12
13
// Koa 中间件
app.use(async (ctx, next) => {
console.log('1-开始');
await next(); // 等待内层异步操作完全结束
console.log('1-结束(此时内层异步已完成)');
});

app.use(async (ctx) => {
console.log('2-开始异步操作');
await new Promise(resolve => setTimeout(resolve, 1000)); // 模拟异步
console.log('2-异步操作完成');
ctx.body = 'Done';
});

Koa 输出(时序完美)

1
2
3
4
5
1-开始
2-开始异步操作
(等待1秒)
2-异步操作完成
1-结束(此时内层异步已完成)

Express 异步场景(时序混乱,需手动处理)

1
2
3
4
5
6
7
8
9
10
11
12
13
// Express 中间件
app.use((req, res, next) => {
console.log('1-开始');
next(); // 不会等待,直接继续执行
console.log('1-结束(此时内层异步还没完成!)');
});

app.use(async (req, res) => {
console.log('2-开始异步操作');
await new Promise(resolve => setTimeout(resolve, 1000));
console.log('2-异步操作完成');
res.send('Done');
});

Express 输出(时序混乱)

1
2
3
4
5
1-开始
2-开始异步操作
1-结束(此时内层异步还没完成!)
(等待1秒)
2-异步操作完成

Express 要实现 Koa 那样的异步等待,需要手动把 next() 包装成 Promise 并 await,代码会非常冗余,这也是 Koa 洋葱模型的核心优势。


四、总结

  • Koa:是真正的洋葱模型,基于 async/await 实现优雅的双向执行,每个中间件都能清晰地控制“请求进来时”和“响应出去时”的逻辑,异步处理极其丝滑,适合做复杂的切面逻辑(如全链路日志、性能埋点、统一错误处理、响应格式包装)。
  • Express:是线性顺序执行模型,中间件单向流转,虽然可以通过在 next() 后写代码模拟部分后置逻辑,但异步时序控制困难,不是真正的洋葱模型,更适合做简单的请求处理和路由分发。

nodejs开发重点
https://cszy.top/20251007-nodejs开发重点/
作者
csorz
发布于
2025年10月7日
许可协议