Node的
events模块只提供了一个EventEmitter类,这个类实现了Node异步事件驱动的基本模式(发布订阅模式)
const EventEmitter = require('events')
Node.js 几乎所有的模块都继承了这个类
class MyEmitter extends EventEmitter {}
// 创建实例
const myEmitter = new MyEmitter()
// 注册事件监听器:使用`on`、`addListener`或`prependListener`
// emit触发事件
// removeListener || off 移除事件
关于其常见的方法如下:
- emitter.addListener(eventName, listener) :添加监听事件到事件数组尾部
- emitter.on(eventName, listener):同上
- emitter.prependListener(eventName, listener):添加监听事件到事件数组头部
- emitter.emit(eventName[, ...args]):触发类型为 eventName 的监听事件
- emitter.removeListener(): 同下
- emitter.off(eventName, listener):移除类型为 eventName 的监听事件
- emitter.once(eventName, listener):添加类型为 eventName 的监听事件,以后只能执行一次并删除
- emitter.removeAllListeners([eventName]): 移除全部类型为 eventName 的监听事件
发布订阅模式可以看做是观察者模式的一个变体:多了一个事件通道,比观察者模式更加灵活和可扩展
⚠️ 如果在事件处理函数中抛出异常,会导致Nodejs进程崩溃,应使用try catch捕获或者process.on(uncaughtException) || process.on('unhandledRejection')
场景:
比如 fs.readStream 对象会在文件被打开的时候触发一个事件
这些产生事件的对象都是 events.EventEmitter 的实例
- 这些对象有一个
eventEmitter.on()函数,用于将一个或多个函数绑定到命名事件上
实现一个发布订阅模式 :
class EventEmitter{
constructor(){
this.events= {}
}
// 订阅
on(eventName, callback){
if(!this.events[eventName]){
this.events[eventName] = []
}
console.log("订阅事件", this.events[eventName]);
this.events[eventName].push(callback);
}
// 添加事件到头部
prependListener(eventName, callback) {
if (!this.events[eventName]) {
this.events[eventName] = [];
}
this.events[eventName].unshift(callback);
}
// 取消订阅
off(eventName,callback){
if(!this.events[eventName]){
return
}
this.events[eventName] = this.events[eventName].filter(fn=> fn!=callback)
}
emit(eventName,...args){
if(this.events[eventName]){
this.events[eventName].forEach((fn)=>fn(...args))
}
}
once(eventName, callback) {
this.on(eventName, this._onceWrap(eventName, callback, this));
}
_onceWrap(eventName, callback, target) {
const state = {
fired: false,
callback,
eventName ,
target
};
const wrapFn = this._onceWrapper.bind(state);
state.wrapFn = wrapFn;
return wrapFn;
}
_onceWrapper(...args) {
if (!this.fired) {
this.fired = true;
Reflect.apply(this.callback, this.target, args);
this.target.off(this.type, this.wrapFn);
}
}
}
const eventBus = new EventEmitter();
console.log(eventBus);
eventBus.on('myClick', (data)=>{
console.log('页面1监听处理:', data)
})
eventBus.on('myClick', (data)=>{
console.log('页面2监听处理:', data)
})
eventBus.emit('myClick', 'hello')
eventBus.emit('myClick', 'world')