第一章: Node.js平台
1.Node.js开发理念
- 小核心
- 小模块
- 小接触面
- 简单实用
2.Node.js的工作原理
1.I/O是慢速操作
2.阻塞式I/O
3.非阻塞式的I/O
4.事件多路分离
5.reactor模式
6.Node.js的I/O引擎 - Libuv
7.Node.js的全套结构
3. Node.js平台之中的JavaScript
- 放心使用最新版的JavaScript
- 模块系统
- 访问操作系统中的各项服务
- 运行原生代码
第二章:模块系统
1. 为什么需要模块
2.JavaScript与Node.js的模块系统
3.模块系统及其模式
revealing module
通过过IIFE(immediately invoked function expression) 创建一个私有作用于,并且通过闭包的形式将export内容导出
4. CommonJS模块
自制的模块加载器
通过CommonJS系统来加载模块,本身就应该实现同步操作,以确保多个模块能够按照正确的依赖顺序得到引入。
const originalRequire = require
const fs = originalRequire('fs')
function loadModule (filename, module, require) {
//同步通过readFileSync读取模块内容
const wrappedSrc =
`(function (module, exports, require) {
${fs.readFileSync(filename, 'utf8')}
})(module, module.exports, require)`
eval(wrappedSrc)
}
require = function require (moduleName) {
console.log(`Require invoked for module: ${moduleName}`)
const id = require.resolve(moduleName) // ①
if (require.cache[id]) { // ②
return require.cache[id].exports
}
// module metadata
const module = { // ③
exports: {},
id
}
// Update the cache
require.cache[id] = module // ④
// load the module
loadModule(id, module, require) // ⑤
// return exported variables
return module.exports // ⑥
}
require.cache = {}
require.resolve = (moduleName) => {
// reuse the original resolving algorithm for simplicity
return originalRequire.resolve(moduleName)
}
// Load the entry point using our homemade 'require'
require(process.argv[2])
定义模块
module.exports & exports
require函数是同步函数
与之相对应的module.exports 的赋值操作,也必须是同步的
模块解析算法
即对应require.resolve函数
模块缓存
通过缓存能够实现效率的提升
除此之外:
5. 定义模块所用的模式
命名导出模式
函数导出模式
module.exports = () => {}
这种模式可以和命名导出模式结合
类导出模式
实例导出模式
利用require()函数的缓存机制,把构造器或工厂所制作的实例缓存起来,以保持其状态,并在多个模式之间共享该实例
通过monkey patching模式修改其他模块或全局作用域
6.ECMAScript模块
能支持循环依赖,而且能够异步加载模块;
但是ES模块是静态的,引入模块语句必须放在顶层,而且必须放在控制语句之外;受引用模块,只能使用常量字符串,不能是变量表达式。这使得ESM能够tree-shaking
在nodejs平台中使用ESM
命名导出和命名引入
命名导出支持自动引入与自动补全功能
namespace import
ESM要求用户必须把要引入的那个模块的文件扩展名写出来
命名导出对dead code elimination更加有利
默认导出 & 默认引入
混用命名导出与默认导出
类似react
模块标识符
- relative specifier
- absolute specifier file:///opt/nodejs/…
- bare specifier
- deep import specifier
- browser supper http URL import
异步引入
提供应对特殊场景的async import / dynamic import
import() : Promise
详细解释模块的加载过程
载入模块所经历的各个阶段
- Construction 找出所有import深度递归加载每个模块的内容,每个模块只访问一次
- Instantiation 针对每个导出实体,内存中保留一个带名称引用,但不赋值, 并link各个模块之间的依赖关系
- Evaluatiion: 后序的深度优先执行,保证每个执行模块的依赖都已经初始化
只读的live绑定
解析循环依赖
修改其他模块
直接修改命名空间或者默认导出会出现不一致问题
可以使用module包中的syncBuiltinESMExports()
7.ESM与CommonJS之间的区别以及交互的使用技巧
ESM是在严格模式下运行的
ESM不支持CommonJS提供的某些引用
filename, dirname => import.meta (fileURLToPath, dirname)
require => createRequire(module) (倒入json文件
commonjs中this指向exports的引用
在其中一种模块系统里面使用另一种模块
import只能引入Common默认导出的东西
8. 小结
第三章: 回调与事件
Callback模式
continuation-passing style (CPS)
某个函数究竟是同步函数,还是异步函数?
- 有的函数无法判断是同步还是异步
- 在同一个函数里混用同步与异步所带来的危害
- 把API设计成同步的
-
在Node.js里面定义回调的惯例
把表示回调的那个参数放在最后
- 如果回调结果里面有错误信息时这项信息应总排在首位
- 播报错误
- 未捕获的异常
Observer 模式
1. EventEmitter
2. 创建并使用EventEmitter
3. 播报错误信息
4. 让任何一个对象都能为监听器观察
5. EventEmitter & memory leak
6. 同步事件与异步事件
和callback模式中同步 / 异步 出现的问题一样
必须保证使用异步注册使得,注册比事件触发提早执行
7. EventEmitter 与 Callback 之间的对比
8. Callback with EventEmitter
把结果和流程都传递给用户
第四章:利用回调实现异步控制流模式
异步编程所遇到的困难
1. 创建简单的网页爬虫
2. callback hell
涉及回调的编程技巧与控制流模式
1. 编写回调逻辑时所应遵循的原则
2. 运用相关的规则编写回调
3. 顺序执行
4. 平行执行
5. 限制任务数量的平行执行
第五章: 利用Promise与async/await实现异步控制流模式
Promise
1. 什么是Promise?
2. Promises/A+ & thenable
3. Promise API
4. 创建Promise
5. 将回调方案改成Promise方案
6. 顺序执行与迭代
7. 平行执行
8. 限制任务数量的平行执行
第六章:用Stream编程
1. 理解stream在Node.js平台中的重要作用
缓冲模式与流模式
流模式在空间占用方便的优势
- 用缓冲模式的API把文件压缩成GZIP格式
用流模式的API把文件压缩成GZIP格式
Readable
- Writable
- Duplex
-
Readable Stream
通过流对象读取数据
- 非流动模式 “readable”
readable.read([size])
- 流动模式 “data”
- ?异步迭代器
- 非流动模式 “readable”
实现自己的Readable Stream
向stream中写入数据
- backpressure
- drain
- 实现Writable Stream
-
Duplex Stream
Transform Stream
实现Transform流
- 简化版的定制方案
-
PassThrough Stream
观察数据的流动情况(数据不处理,原样传递
- Late piping
lazy Stream
lazystream npm pkg
原理是通过passThrough Stream 代理,当首次_read的时候,再创建需要的流
用管道连接流对象
- 处理管道之中的错误
- 通过pipeline()方法可以更好地处理管道中的错误
3. 用Stream实现异步控制流模式
顺序执行
无序的平行执行
在有限的缓冲区中保存获得的值
管道模式
Combine Streams
pumpify npm pkg
fork Stream
注意不要产生副作用
merge Streams
mux/demux模式
packet switching问题
- 构建一款远程的日志记录器
- 对象流的mux / demux