EventEmitter类
events与EventEmitter
EventEmitter常见API
const events = require('events');
const e = new events()
function fn1(){
console.log('event1');
}
e.on('event1',fn1)
e.on('event1',fn1)
e.emit('event1') // event1 event1-2
e.once('event2',() => {
console.log('event2');
})
//只调用一次
e.emit('event2') //event2
e.emit('event2') // 不打印
//移除event1事件
e.off('event1',fn1)
发布订阅模式
定义对象间一对多的依赖关系
发布订阅可以解决什么问题?
订阅者把消息注册在消息调度中心,发布者在需要某消息的时候,去消息调度中心去查找相应的消息。
发布订阅的要素
- 缓存队列,存放订阅者信息
- 具有增加、删除订阅的能力
- 状态改变时通知所有订阅者执行监听
浏览器中的EventLoop
完整事件环执行顺序
- 从上至下执行所有的同步代码
- 执行过程中将遇到宏任务与微任务添加至相应的队列
- 同步代码执行完毕后,执行满足条件的微任务回调
- 微任务队列执行完毕后,执行所有满足条件的宏任务回调
- 循环事件环操作
注意:在执行每个宏任务前都要清空微任务队列
Nodejs完整事件环
- 执行同步代码,将不同的任务添加至相应的队列
- 所有同步代码执行后会执行满足条件的微任务
- 所有微任务执行后会执行timer队列中满足的宏任务
- timer中的所有宏任务执行完成后会依次切换队列
注意:在完成队列切换前都要清空微任务队列
核心模块Stream
Node.js中文件操作系统和网络模块均实现了流接口,Node.js中的流就是处理流式数据的抽象接口。
应用程序中为什么使用流来处理数据?
常见的数据读取问题
- 同步读取资源文件,用户需要等待数据读取完成
- 资源文件最终一次性加载至内存,开销较大
为了解决上述问题,所有采用流的形式来操作数据
流处理数据的优势
- 事件效率:流的分段处理可以同时操作多个数据
- 空间效率:同一时间流无须占据大内存空间
- 使用方便:流配合管理,扩展程序变得简单
Node.js内置了stream,它实现了流操作对象
Node.js中流的分类
可读流 (生产供程序消费数据的流)
可读流中的两种模式:
- 流动模式 ( flowing ) :数据自动从系统底层读取,并通过事件,尽可能快地提供给应用程序。
- 暂停模式 ( paused ),必须显式的调用
read()
读取数据。
可写流(用于消费数据的流)
Duplex(双工流,即可读又可写)
Transform(双工流)
write执行流程
- 第一次调用write方法时是将数据直接写入到文件中
- 第二次开始write方法就是将数据写入至缓存中
- 生产速度和消费速度是不一样的,一般情况下生产速度要比消费速度快很多
- 当读取数据大于缓存内存的时候,将可读流的模块修改为暂停模式
- 当数据生产者暂停之后,消费者会慢慢的笑话它内部缓存中的数据,知道可以再次被执行写入操作
- 当缓冲区可以继续写入数据时调用drain事件