手写一个 node 中的发布订阅模式

2023-05-27 0 494

我们好,又碰面了,我是上首诗说滚去写销售业务标识符,然后被产品煎熬到现如今才有点儿空余时间就立刻爬来写诗的爱好自学和科学知识的开发人员(不断句,干净利落,自己甚至觉得有点儿小自豪),好了,转至自问自答,那次他们聊了聊有关该事件环的科学知识,当中他们提及了一点是说 node 中的api绝大部分都是通过反弹表达式和正式发布订户的商业模式来展开的,ok,划个重点项目,正式发布订户!这是他们那时该文的主轴,也是整座node自学中极为关键的一小部分,那时就带我们来记事本两个node中的正式发布订户~

正式发布订户

以后他们见过面正式发布订户的商业模式是,当两个使用者订户了许多该事件后,如果那些该事件促发了,那他们要是去继续执行使用者在订户该事件的这时候表述的表达式。

单纯的举个范例,比如他们 js 中的 addEventListener 和 jQuery 中的 on,这两个较之他们都很熟识,都是为某一 dom 原素展开存取两个该事件,比如他们为两个按键存取了 click 该事件,所以当那个按键促发了 click 该事件后,所以他们存取这时候表述的表达式也会被继续执行,

Events

绝大多数 Node.js 核心理念 API 都选用惯常的异步该设计模式构架,当中这类类别的第一类(促发器)会Jhunjhunun促发重新命名该事件来调用表达式第一类(H55N)。

node 两个核心理念组件是 events,他实现的机能只不过是他们的正式发布订户商业模式,下面的说明只不过是说明了 events 那个组件在他们 node 的许多核心理念 api 些十分关键的作用,比如说他们的 tcp,http,流那些都加进了他们的 events 组件。

他们就来看一看events组件中的那些核心理念方法和特性:

具体来说是第二块,这几块主要是说明了node中的一个对于追加该事件或是去除该事件这时候要先促发这相关联的该事件

newListener 该事件,node中定两个这样两个规范,是说当他们订户任何新该事件的这时候都会促发两个 newListener 该事件,传入的参数是订户的新该事件名removeListener 该事件,同上,当他们去除两个该事件的该事件就会促发 removeListener 该事件。

这一小部分是介绍该事件的H55N数量相关的表达式

EventEmitter.defaultMaxListeners,规定了每个该事件的H55N(也是反弹表达式)的最大数量,默认是10,当超过那个数量的这时候会报两个警告emitter.setMaxListeners(n) 设置最大监听数emitter.getMaxListeners 返回 EventEmitter 当前的最大H55N限制值

这一小部分主要是对于注册的该事件或是某一已注册的该事件的监听数数组做的操作

emitter.eventNames 返回两个列出促发器已注册H55N的该事件的数组emitter.listenerCount(eventName) 返回正在监听名为 eventName 的该事件的H55N的数量emitter.listeners(eventName) 返回名为 eventName 的该事件的H55N数组的副本

这部分是events的核心理念方法,on存取监听,once存取的该事件只促发一次,emit用来发射该事件

emitter.addListener 也是on的别名,是订户某两个该事件比如 my.on(buy,()=>{console.log(没钱了)})emitter.on(eventName, listener) 添加 listener 表达式到名为 eventName 的该事件的H55N数组的末尾。 不会检查 listener 是否已被添加。 多次调用并传入相同的 eventName 和 listener 会导致 listener 被添加与调用多次。emitter.once(eventName, listener) 添加两个单次 listener 表达式到名为 eventName 的该事件。 下次促发 eventName 事件时,H55N会被去除,然后调用emitter.prependListener(eventName, listener) 和 on 方法类似,但是调用那个方法会吧H55N添加到数组的首项emitter.prependOnceListener(eventName, listener) 和 once 类似,也依然是讲H55N添加到数组首项emitter.emit 发射该事件,会按照注册该事件这时候放置的反弹表达式的顺序展开继续执行

这一小部分是做该事件去除

emitter.removeAllListeners([eventName]) 去除全部或指定 eventName 的H55Nemitter.removeListener(eventName, listener)从名为 eventName 的该事件的H55N数组中去除指定的 listeneremitter.off(eventName, listener) 是removeListener的别名

My-EventEmitter

老套路,既然他们都知道了那些方法是什么意思 所以他们就跟着来记事本两个 EventEmitter!

function EventEmitter(){

this._events = {} ;// 该事件库

this.count = 0 ; // 同类该事件最大的监听数

}

// 最大监听数默认是10

EventEmitter.defaultMaxListeners = 10;

EventEmitter.prototype.getMaxListeners = function(){

return this.count || EventEmitter.defaultMaxListeners

}

// 设置最大监听数

EventEmitter.prototype.setMaxListeners = function(n){

this.count = n;

return this

}

// addListener 和 on同样的作用

EventEmitter.prototype.addListener = EventEmitter.prototype.on;

/**

实现on方法

@param {string} eventName 订户该事件名

@param {function} callback 反弹表达式

@param {boolean} flag 是否添加到表达式列表的第一位(是否第一次继续执行)

/

EventEmitter.prototype.on = function(eventName,callback,flag){

// 通常情况下 他们使用EventEmitter是通过util.inherits来继承EventEmitter的公有方法,

// 而EventEmitter的_events特性是在实例上的 因此 如果检测到是通过继承拿到的

// 所以就为那个类添加_events特性

if(!this._events) this._events = Object.create(null);

// 如果该事件名不是newListener 所以检测如果订户了newListener所以就继续执行

if(eventName !== newListener && this._events[“newListener”] && this._events[“newListener”].length){

this._events[newListener].forEach(fn =>fn(eventName));

}

if(this._events[eventName]){

// 如果以后添加过那个该事件

if(flag){

this._events[eventName].unshift(callback)

}else{

this._events[eventName].push(callback)

}

}else{

this._events[eventName] = [callback]

}

// 判断订户该事件数 超过最大个数 打印警告

if (this._events[eventName].length >= this.getMaxListeners()) {

console.warn(MaxListenersExceededWarning);

}

}

/*

返回当前订户的该事件名集合

/

EventEmitter.prototype.eventNames = function(){

return Object.keys(this._events)

}

/*

返回订户的该事件存取的表达式个数

@param {string} eventName

/

EventEmitter.prototype.listenerCount = function(eventName){

return (this._events[eventName] || []).length

}

/*

返回订户的该事件存取表达式的copy

@param {string} eventName

*/

EventEmitter.prototype.listeners = function(eventName){

return […(this._events[eventName] || [])]

}

EventEmitter.prototype.off = EventEmitter.prototype.removeListener;

/**

去除某一该事件下的继续执行表达式

@param {string} eventName

@param {function} callback

/

EventEmitter.prototype.removeListener = function(eventName,callback){

if(this._events[eventName]){

this._events[eventName] = this._events[eventName].filter((fn) => {

return fn != callback && fn.realCallback !== callback;

// 这里判断了fn是不是等于callback,同时也解决他们因为once操作而把原有的反弹表达式包裹一层的问题,

// 通过暴露出来的原有反弹作对比

})

}

return this

}

/*

去除某一该事件的所有反弹

@param {string} eventName

/

EventEmitter.prototype.removeAllListeners = function(eventName){

if(this._events[eventName]){

this._events[eventName] = []

}

return this

}

/*

添加两个单次 listener 表达式到名为 eventName 的该事件。 下次促发 eventName 该事件时,H55N会被去除,然后调用。

@param {string} eventName

@param {function} callback

@param {boolean} flag

/

EventEmitter.prototype.once = function(eventName,callback,flag){

function wrap(){

callback();

this.removeListener(eventName,wrap)

}

wrap.realCallback = callback; // 这里因为once的反弹表达式被重新包裹了一层

// 因此当你removeListener的这时候如果用原来的fn去判断是否相等的话就判断不到了,

// 因此需要把原来的fn暴露到两个特性上,方便删除操作的这时候去做对比

this.on(eventName,wrap,flag)

return this;

}

/*

向数组前面添加该事件

@param {string} eventName

@param {function} callback

/

EventEmitter.prototype.prependListener = function (eventName, callback) {

this.on(eventName, callback, true);

}

/*

向数组前面添加该事件 并且只继续执行一次

@param {string} eventName

@param {function} callback

/

EventEmitter.prototype.prependOnceListener = function(eventName, callback){

this.once(eventName,callback,true);

}

/*

促发该事件

@param {string} eventName

*/

EventEmitter.prototype.emit = function (eventName) {

if (this._events[eventName]) {

this._events[eventName].forEach(fn => {

fn.call(this);

});

}

}

跟着思路来了一遍,是不是发现突然开窍,大喊一声,学会了!快删!

举报/反馈

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务