Node
:::info
📦 基于 Node.js 14.x
LTS 版本
:::
basic and intro.
Node 的特点
Strength
- Asynchronized I/O
- Events and Callbacks
- Single -Thread
- Multi-platforms Support
Weakness
- 不擅长 CPU 密集型任务
- 无法更好地运用多核处理器
- 单线程的健壮性问题(遇到错误会导致整个程序退出)
- 异步程序测试不是那么容易
应用场景
- I/O 密集型
- 数据中介
- 服务端工具
- JS 全栈
- …
Node and Modules
CommonJS 规范
require/define/exports
的运行:
(function (exports, require, module, __filename, __dirname) { // The code we write will be here});
var http = require('http');
http.newMethod = function () {};
module.exports = http;
Attention: Under the hood in the Node module system, the result of require is cached after the first time it’s called for a specific module. This means multiple calls to require('./mmm')
will always return the same instance of the mmm module.
Node 模块的实现
Node模块分为两类:核心模块(已经编译好的二进制执行文件)和文件模块(运行时动态加载,需要进行路径分析、文件定位以及编译执行的过程,基于V8引擎)。
- JS 文件:vm 原生模块的:
runInThisContext()
方法执行,类似于eval()
- JSON 文件:
JSON.parse()
的方式生成对象 - C/C++ 文件: 利用
process.dlopen()
方法进行加载,并通过不同的抽象层次进行封装。
Node的模块,具有缓存优先加载的策略,编译和执行后的对象都会被缓存以提高效率。
- 路径分析:递归到根目录去查询
node_modules
文件夹中是否有对应需要的模块。 - 文件定位:
.js
.node
.json
的顺序加载 - 编译执行
编程范式
Async I/O
Async Patterns
Node Core Modules
- Buffer
- Stream
- File & I/O
- OS
- Process
- Cluster
- WorkerThread:多线程操作
- Net: TCP or IPC servers
- HTTP
- HTTP/2
http.Server
http.Agent
http.createServer()
http.request(...)
- HTTPS
- UPD(dgram):UDP 协议相关 API
- TLS(SSL):SSL 连接相关 API
- DNS:DNS 查询相关 API
- Crypto:加解密和证书、签名相关的 API
- Zlib:Gzip 关联操作(压缩 / 解压缩)
Sever Side Programming
具体的实现代码我们可以参考 Express 等框架或者工具的部分源码来理解它们是如何运作的。
ME | 如果要真正学好 Node Web程序设计的话,有必要认真理解 Express 等架构和实现细节。当然,现在我更加推荐自己去认真阅读 https://eggjs.org/ 中对 WebFramework 的设计和实现。
基础功能
- 请求方法
ServerRequest
ServerResponse
- 路径解析和查询字符串
url.parse()
querystring.parse()
- Cookie
parseCookie(req.headers.cookie)
- Session
req.session
贴加在对应的 Cookie 中- 查询字符串的方式来实现
- 考虑 Session 与 内存,以及安全的问题
- 缓存技术
- 添加 Expires 或 Cache-Control 到报文头中
If-Modified-Since
/Last-Modified
字段 - 配置 ETags
- 让 Ajax 缓存
- 添加 Expires 或 Cache-Control 到报文头中
- Basic 认证
数据库
参考 MangoDB
数据上传
- 表单数据:
Content-Type: application/x-www-form-urlencoded
, 对应querystring.parse(req.rawBody)
方法获得请求数据 - 其它格式
req.body
获得相关数据 - 附件上传
Content-Type: application/form-data
对应使用对应的解析器执行 - 数据上传和安全
- 内存限制
- 防止 Cross-Site Request Forgery CSRF 方法在于验证 token
路由解析
- 文件路径
- 静态文件
- 动态文件(因为 Node 的服务脚本和业务脚本是一体的,所以不需要所谓的动态方式实现)
- MVC
- 实现方法
- 基于正则的路由匹配
- 进行剩余的参数解析
- 自然映射
- RESTful
Middleware 中间件
理解中间件的概念:用于简化和隔离基础设施与业务逻辑之间的细节,让开发者能够关注在业务上的开发,以达到提高开发效率的目的。
页面渲染
- 内容响应
- MIME响应
var mime = require('mime')
- 附件下载
- 响应JSON
- 响应跳转
- MIME响应
- 视图渲染
- 模板系统
Bigpipe 思路
先传输整个空白框架,再逐步向框架中填入数据。以此提高响应速度。
调试
- 使用
node-debug app.js
即node inspector
进行调试。使用 Chrome 自带的 devTool 进行可视化界面的调试。 - 使用
node debug app.js
即 node 自带的断点调试工具进行调试。参考 官方 API Doc
测试
编写可测试的代码的原则:
- 单一职责
- 接口抽象
- 层次分离
单元测试
- 断言:用于保证单元测试中最小单元是否正常的检测方法。
- 测试框架:提供测试服务,但是本身不参与测试。e.g. mocha
- 测试代码中的文件组织:将测试框架和服务模块加入
devDependencies
中声明,而测试代码,存放于test
目录中 - 测试用例配置应该规范、清晰合理。同时在异步测试的时候,需要配置好超时的情形。
- 测试覆盖率
- 私有方法、属性的测试:rewire 的思想
- 考虑 工程工具自动化测试,提高效率,利用 Gulp 等工具。
性能测试
基准测试
benchmark
测试能够组织基准测试
压力测试
对:吞吐率、响应时间以及并发数等进行分析、测试。
利用:ab
siege
http_load
等工具来构造压力测试。
产品化
项目工程化
- 可能的目录结构
- 说明文件
- README.md
- History.md
- INSTALL.md
- Makefile
- benchmark // 基准测试
- lib // 没有模块化的项目
- logs
- config
- bin
- tools
- doc // 文档
- test // 测试
- proxy // 数据代理
- dispatch.js // 多进程管理
- app
- assets
- assets.json // 静态文件和CDN路径的映射文件
- view
- controller
- route
- model
- …
- node_modules
- 说明文件
- 构建工具
- 编码规范
- 代码审查
部署流程
- 部署环境:代码 —> Stage —> pre-release —> product
- 部署操作:
nohup node app.js &
以不挂断进程的方式进行 - 利用 bash 脚本进行更为有效地管理
性能管理
- 动静分离
- 启用缓存
- 多进程架构的配置
cluster
模块 - 读写分离
- … 还有非常多的优化建议需要自寻总结和理解 + 探索
日志
- 访问日志
- 异常日志
- 日志处理:存储、分析和销毁。
监控报警
- 日志监控
- 响应时间、进程、磁盘、内存、CPU占用、CPU Load、I/O负载、网络监控
- 应用状态监控
- DNS监控
- …
报警机制的实现:邮件机制(nodemailer
模块)、短信、电话等
稳定性
WIP
使用 Node 开发工具
Ref
- 10 Node Frameworks to Use in 2019
- Github Awesome Node.js
- Github awesome node.js lib
- 2017 Top Node.js Articles
- Node CLI Tools Development Guide
- 《深入浅出Node》
- Best Practice of Node Production
- Node.js 来一打 C++ 扩展
公司内部: