- 通过EventEmitter类实现事件统一管理
-
events与EventEmitter
nodejs是基于事件驱动的异步操作架构,内置events模块
- events模块提供了EventEmitter类
nodejs中很多内置核心模块继承了EventEmitter,例如FS http
EventEmittr常见API
on: 添加当事件被触发时调用的回调函数
- emit: 触发事件,按照注册的顺序同步调用每个事件监听器,(第二个参数可以传参)
- once:添加当事件在注册之后首次被触发时调用的回调函数,调用后会被删除掉 ```javascript const EventEmitter = require(‘events’)
const ev = new EventEmitter() // 执行顺序是注册时的顺序 // 1. on ev.on(‘事件1’,() => { console.log(‘事件1执行了’); })
ev.on(‘事件1’,() => { console.log(‘事件1执行了—-2’); })
// emit 多次触发多次执行 ev.emit(‘事件1’) ev.emit(‘事件1’)
// 2. once ev.once(‘事件1’,() => { console.log(‘事件1 once执行了’); }) ev.once(‘事件1’,() => { console.log(‘事件1 once执行了’); }) ev.emit(‘事件1’) // ev.emit(‘事件1’) 第二次监听,不执行,因为删掉了
// 3. off 删除事件 let cbFn = (…args) => { console.log(“事件1执行”); console.log(args); }; ev.on(“事件1”, cbFn);
// 传参 ev.emit(“事件1”, 1, 2);
// ev.off(“事件1”, cbFn); ev.emit(“事件1”, 1, 2);
ev.on(“事件1”, function () { console.log(this); }); ev.on(“事件2”, function () { console.log(this); }); /* EventEmitter { _events: [Object: null prototype] { ‘事件1’: [Function (anonymous)], ‘事件2’: [Function (anonymous)] }, _eventsCount: 2, _maxListeners: undefined,
} */
// 相同的事件,有多少个事件监听,_events数组中就会加多少个 ev.emit(“事件1”); ev.emit(“事件2”);
const fs = require(‘fs’) const crt = fs.createReadStream() crt.on(‘data’)
<a name="u8ZoW"></a>
### 发布订阅模式
- 是一个模型,定义了对象间一对多的依赖关系,不同对象间实现了解耦,完全做到不认识彼此
- 发布订阅可以解决什么问题?
- 答案:连续使用多个异步API, 这些异步又互相依赖彼此的执行结果,这个时候会产生很多回调嵌套,发布订阅模式很好做好
- NodeJs中的event loop中的事件队列
- 发布订阅要素
- 缓存队列,存放订阅者信息
- 具有增加、删除订阅的能力
- 状态改变时通知所有订阅者执行监听
- 发布订阅模式和观察者模式区别
- 发布订阅中存在调度中心(观察者模式中没有)
- 状态发生改变时,发布订阅无须主动通知(由调度中心决定订阅之前的信息如何执行)
![发布订阅模式.png](https://cdn.nlark.com/yuque/0/2022/png/22628793/1651569406062-66884868-a152-4aff-bce9-7b0c8e6092e4.png#clientId=u7fdd22fa-7fcf-4&crop=0&crop=0&crop=1&crop=1&from=ui&id=u350cf1f4&margin=%5Bobject%20Object%5D&name=%E5%8F%91%E5%B8%83%E8%AE%A2%E9%98%85%E6%A8%A1%E5%BC%8F.png&originHeight=476&originWidth=933&originalType=binary&ratio=1&rotation=0&showTitle=false&size=99980&status=done&style=none&taskId=u150aa13f-0d48-464d-8ba9-10493f43100&title=)
```javascript
class PubSub {
constructor() {
this._events = {};
}
// 注册
subscribe(event, callback) {
// 查找监听是否存在
if (this._events[event]) {
// 如果event存在,所以我们只需要往后添加当前次监听操作
this._events[event].push(callback);
} else {
// 之前没有订阅过次事件,创建数组,放入事件
this._events[event] = [callback];
}
}
// 发布,发布哪个事件,传入参数
publish(event, ...args) {
const items = this._events[event];
if (items && items.length) {
items.forEach((callback) => {
// 绑定this, 传入参数
callback.call(this, ...args);
});
}
}
}
let ps = new PubSub()
ps.subscribe('事件1',() => {
console.log('事件1 执行了');
})
ps.subscribe('事件2',() => {
console.log('事件2 执行了');
})
ps.publish('事件1')
ps.publish('事件2')
EventEmitter模拟
function MyEvent() {
// 准备一个数据结构用于缓存订阅者的一些信息
this._events = Object.create(null); // 创建不带任何原型的空对象
}
// on 操作实现
MyEvent.prototype.on = function (type, callback) {
// 判断当前次的事件是否已经存在
if (this._events[type]) {
this._events[type].push(callback);
} else {
this._events[type] = [callback];
}
};
// emit事件实现
MyEvent.prototype.emit = function (type, ...args) {
if (this._events && this._events[type].length) {
this._events[type].forEach((callback) => {
callback.call(this, ...args);
});
} else {
}
};
// off取消事件监听
MyEvent.prototype.off = function (type, callback) {
// 先判断当前type事件监听是否存在,如果存在则取消指定的监听
if (this._events && this._events[type]) {
this._events[type] = this._events[type].filter((item) => {
return item !== callback && item.link !== callback;
// 判断一下当前回调和item的link(once函数里面建立一层关系)是否一样,如果一样那就过滤掉 留下不被取消的
});
}
};
// once
MyEvent.prototype.once = function (type, callback) {
let foo = function (...args) {
callback.call(this, ...args);
this.off(type, foo); // 执行完取消掉这个函数
};
// 建立一层关系
foo.link = callback
// 先触发,再取消
this.on(type, foo);
// this.off(type, callback);
};
let ev = new MyEvent();
let fn = function (...data) {
console.log("事件1执行了");
console.log(data);
};
// ev.on('事件1', fn)
// ev.on('事件1', () => {
// console.log('事件1');
// })
// ev.emit('事件1',1,2)
// ev.emit('事件1',1,2)
ev.once("事件1", fn);
ev.off("事件1", fn);
ev.emit("事件1", "前");
// ev.emit("事件1", "前1"); // once第二次不生效的
// ev.off("事件1", fn); // 取消了事件1监听
// ev.emit("事件1", "后");