eventemitter学习一什么是EventEmitter?EventEmitter(事件派发器)是一个对事件进行

JavaScript事件最核心的包括事件监听(addListener)、事件触发(emit)、事件删除(removeListener),理解如下:

考虑一个DOM事件:

//Typescriptconstbutton=document.querySelector('button');button.addEventListener("click",(event)=>{//dosomethingwiththeevent})我们向按钮单击事件添加了一个listener(监听器),并且已经订阅了一个正在被发出的事件,当事件发生时会触发回调。每次单击该按钮时,都会发出该事件,而该事件会触发回调。

当处理现有代码库时,或许需要触发自定义事件。不像单击按钮这样的特定DOM事件,而是假设想基于其他触发器发出一个事件,并得到一个事件响应。我们需要一个自定义事件派发器来实现这一点。

事件派发器是一种模式,它监听一个已命名的事件,触发回调,然后发出该事件并附带一个值。有时这被称为“发布/订阅”模型或监听器。它们指的是同一件事。

发布—订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。

在JavaScript开发中,我们一般用事件模型来替代传统的发布—订阅模式。

发布者有一个订阅者缓存队列

发布者有增加和删除订阅者的方法

发布者状态改变,需要notify方法通知队列中的所有订阅者

js中采用事件回调的方式来更新订阅者,因此订阅者不再需要update方法

下面来模拟下EventEmitter的初步实现

once(eventName,listener){functionwrap(args){listener.apply(this,args);this.removeListener(eventName,wrap);}wrap.cb=listener;//将回调存储起来用于删除时对比this.on(eventName,wrap);}复制代码将回调函数包裹起来,在包裹函数内部移除原回调函数,然后将wrap函数添加进观察者队列。同时要将原回调函数存进wrap中,用在在移除原回调时判断。

this.emmit('newListener',eventName,listener);//触发newListener事件回调复制代码defaultMaxListeners这个静态属性限制了一种事件可以添加的最大回调数量,同时还有配套的setMaxListeners和getMaxListeners方法来设置和获取每个事件可以添加的最大回调数量

setMaxListeners(n){this.maxListeners=n;}getMaxListeners(){returnthis.maxListenersthis.maxListeners:EventEmitter.defaultMaxListeners;}复制代码on方法添加判断;

这对于一个对象由多个模块构成的情况非常有用,能防止某一个键被不小心改写或者覆盖。

用法举例:

letmySymbol=Symbol();//第一种写法leta={};a[mySymbol]='Hello!';//第二种写法leta={[mySymbol]:'Hello!'};//第三种写法leta={};Object.defineProperty(a,mySymbol,{value:'Hello!'});//以上写法都得到同样结果a[mySymbol]//"Hello!"Object.getOwnPropertySymbolsObject.getOwnPropertySymbols()方法返回一个数组,包含给定对象所有自有的Symbol值的属性(包括不可枚举的Symbol值属性)。语法

Object.getOwnPropertySymbols(obj);//参数obj:要获取自有Symbol值属性的对象;返回值一个包含给定对象所有自有的Symbol值的属性的数组。所有的对象在初始化时都不会包含任何的Symbol值属性,除非在对象上显式定义了Symbol值属性,否则该方法会返回一个空数组。

例:获取对象自有的Symbol值属性

vara=Symbol('a');varb=Symbol('b');varobj={};obj[a]=1;obj[b]=2;Object.getOwnPropertySymbols(obj);//[Symbol(a),Symbol(b)]varc=Symbol('c');Object.defineProperty(obj,c,{value:3,enumerate:false,writable:false,configuration:false});Object.getOwnPropertySymbols(obj);//[Symbol(a),Symbol(b),Symbol(c)]三、源码分析EventEmitter3是一个典型的第三方事件库,能够让我们自定义实现多个函数与组件间的通信。

本项目的结构比较清晰,主要包括的内容是:

表示单个事件侦听器的EE

Prototype属性:保存事件与监听器的_events属性

方法的定义

EventEmitter.prototype上的方法定义

为removeListener和on方法别名

prefix和EventEmitter导出

下面对内容进行具体讲解

/***Representationofasingleeventlistener.**@param{Function}fnThelistenerfunction.*@param{*}contextThecontexttoinvokethelistenerwith.*@param{Boolean}[once=false]Specifyifthelistenerisaone-timelistener.*@constructor*@private*/functionEE(fn,context,once){this.fn=fn;this.context=context;this.once=once||false;}EE:

/***Addalistenerforagivenevent.**@param{EventEmitter}emitterReferencetothe`EventEmitter`instance.*@param{(String|Symbol)}eventTheeventname.*@param{Function}fnThelistenerfunction.*@param{*}contextThecontexttoinvokethelistenerwith.*@param{Boolean}onceSpecifyifthelistenerisaone-timelistener.*@returns{EventEmitter}*@private*/functionaddListener(emitter,event,fn,context,once){if(typeoffn!=='function'){thrownewTypeError('Thelistenermustbeafunction');}varlistener=newEE(fn,context||emitter,once),evt=prefixprefix+event:event;if(!emitter._events[evt])emitter._events[evt]=listener,emitter._eventsCount++;elseif(!emitter._events[evt].fn)emitter._events[evt].push(listener);elseemitter._events[evt]=[emitter._events[evt],listener];returnemitter;}addListener:

/***Cleareventbyname.**@param{EventEmitter}emitterReferencetothe`EventEmitter`instance.*@param{(String|Symbol)}evtTheEventname.*@private*/functionclearEvent(emitter,evt){if(--emitter._eventsCount===0)emitter._events=newEvents();elsedeleteemitter._events[evt];}clearEvent:

/***Minimal`EventEmitter`interfacethatismoldedagainsttheNode.js*`EventEmitter`interface.**@constructor*@public*/functionEventEmitter(){this._events=newEvents();this._eventsCount=0;}EventEmitter:

/***Returnanarraylistingtheeventsforwhichtheemitterhasregistered*listeners.**@returns{Array}*@public*/EventEmitter.prototype.eventNames=functioneventNames(){varnames=[],events,name;if(this._eventsCount===0)returnnames;for(namein(events=this._events)){if(has.call(events,name))names.push(prefixname.slice(1):name);}//Object.getOwnPropertySymbols()方法返回一个数组,包含给定对象所有自有的Symbol值的属性(包括不可枚举的Symbol值属性)if(Object.getOwnPropertySymbols){returnnames.concat(Object.getOwnPropertySymbols(events));}returnnames;};EventEmitter.prototype.eventNames:

/***Returnthenumberoflistenerslisteningtoagivenevent.**@param{(String|Symbol)}eventTheeventname.*@returns{Number}Thenumberoflisteners.*@public*/EventEmitter.prototype.listenerCount=functionlistenerCount(event){varevt=prefixprefix+event:event,listeners=this._events[evt];if(!listeners)return0;if(listeners.fn)return1;returnlisteners.length;};EventEmitter.prototype.listenerCount:

/***Addalistenerforagivenevent.**@param{(String|Symbol)}eventTheeventname.*@param{Function}fnThelistenerfunction.*@param{*}[context=this]Thecontexttoinvokethelistenerwith.*@returns{EventEmitter}`this`.*@public*/EventEmitter.prototype.on=functionon(event,fn,context){returnaddListener(this,event,fn,context,false);};EventEmitter.prototype.on:

/***Addaone-timelistenerforagivenevent.**@param{(String|Symbol)}eventTheeventname.*@param{Function}fnThelistenerfunction.*@param{*}[context=this]Thecontexttoinvokethelistenerwith.*@returns{EventEmitter}`this`.*@public*/EventEmitter.prototype.once=functiononce(event,fn,context){returnaddListener(this,event,fn,context,true);};EventEmitter.prototype.once:

/***Removealllisteners,orthoseofthespecifiedevent.**@param{(String|Symbol)}[event]Theeventname.*@returns{EventEmitter}`this`.*@public*/EventEmitter.prototype.removeAllListeners=functionremoveAllListeners(event){varevt;if(event){evt=prefixprefix+event:event;if(this._events[evt])clearEvent(this,evt);}else{this._events=newEvents();this._eventsCount=0;}returnthis;};EventEmitter.prototype.removeAllListeners:

////Aliasmethodsnamesbecausepeoplerolllikethat.//EventEmitter.prototype.off=EventEmitter.prototype.removeListener;EventEmitter.prototype.addListener=EventEmitter.prototype.on;

THE END
1.电子商务网站开发与建设JavaScript中用“>”或“<”操作符比较字符串大小时,它们只会比较这些字符的Unicode编码,而不考虑本地的顺序。 字符串类型的大小判断是一个字符和一个字符的比较,只要有字符不同就停止继续判断并返回比较结果。例如:"aBc"<"ab"; localeCompare方法可以实现汉字按拼音排序。 字符集范围Unicode编码(16进制)Unicode编码...https://www.jianshu.com/p/4168ba8ac876
2.4.手写一个EventEmitter实现事件发布订阅EventEmitter (事件派发器)是 Node.js 的核心模块 events 中的类,用于对 Node.js 中的事件进行统一管理,用 events 特定的 API 对事件进行添加、触发和移除等等,EventEmitter 的核心就是事件触发与事件监听器功能的封装。 简而言之,EventEmitter就是一个典型的发布订阅模式,实现了事件调度中心。 https://www.cnblogs.com/alwaysrun/p/17179936.html
3.检测到可能的EventEmitter内存泄漏检测到可能的EventEmitter内存泄漏 我收到以下警告: (node) warning: possible EventEmitter memory leak detected. 11 listeners added. Use emitter.setMaxListeners() to increase limit. Trace: at EventEmitter.<anonymous> (events.js:139:15) at EventEmitter.<anonymous> (node.js:385:29) at Server.<...https://m.imooc.com/wenda/detail/585770
4.eventemitterEventEmitterTargetClass() emitter[Symbol.toStringTag] emitter[Symbol.iterator]() emitter.entries() emitter.listenerCount(eventName) emitter.clear(eventName) emitter.removeAllListeners(eventName) emitter.on(eventName, listener) emitter.addListener(eventName, listener) ...https://gitee.com/masx200/event-emitter-target/
1.learnmorethemethodsontheeventemitterobjectNode.js - Event Emitter - The Node.js API is based on an event-driven architecture. It includes the events module, which provides the capability to create and handle custom events. The event module contains EventEmitter class. The EventEmitter object emihttps://www.tutorialspoint.com/nodejs/nodejs_event_emitter.htm
2.www.tup.tsinghua.edu.cn/upload/books/yz/086763需要挂载器件库文件。具体步骤参考3.2.4节。在弹出如图3.31所示界面时需要进行修改,修改结果如图3.33所示。 图3.33门级仿真设置 在进行门级仿真之前,VHDL设计文件需进行EDA Netlist Writer操作,获得底层网表文件。设置完成后单击Tools→GATE level Simulation,Quartus Prime会自动调用ModelSim Altera仿真器,弹出如图3.34所示...http://www.tup.tsinghua.edu.cn/upload/books/yz/086763-01.txt
3.如何用JavaScript在服务端写入json文件接下来呢,我们调用fs.createReadStream创建了一个ReadStream对象。ReadStream是Stream,也是EventEmitter。 fs.createReadStream方法原型如下: 第一个参数是文件路径,第二个参数是可选的JSON对象,用来指定打开文件的一些选项,默认值如下: autoClose属性默认为true,读完文件或读取出错时,文件会被自动关闭。fd属性可以关联一个...https://blog.51cto.com/u_16213560/11382713
4.如何实现一个EventEmitter?如何实现eventemitter在JavaScript中,EventEmitter类是一种创建、监听、触发自定义事件的机制。在Node.js中,EventEmitter类是events模块的一部分,但在普通的JavaScript环境中,我们可以自己实现一个简单的EventEmitter。 以下是一个基本的EventEmitter实现: classEventEmitter{ constructor() { ...https://blog.csdn.net/csdn_Levy/article/details/142748103
5.EventEmitter(v5.2.8)EventEmitter EventEmitter 让浏览器支持基于事件的 JavaScript 编程 GitHub仓库 版本: 5.2.8 文件: 全部 https://cdn.bootcdn.net/ajax/libs/EventEmitter/5.2.8/EventEmitter.js https://cdn.bootcdn.net/ajax/libs/EventEmitter/5.2.8/EventEmitter.min.js...https://www.bootcdn.cn/EventEmitter/
6.GitHubPlatform: win32, x64, 15267MB Node version: v13.11.0 CPU: 4 x AMD Ryzen 3 2200U with Radeon Vega Mobile Gfx @ 2495MHz --- EventEmitterHeatUp x 2,897,056 ops/sec ±3.86% (67 runs sampled) EventEmitter x 3,232,934 ops/sec ±3.50% (65 runs sampled) EventEmitter2 x 12,261...https://github.com/EventEmitter2/EventEmitter2
7.eventemitter3EventEmitter3 is a high performance EventEmitter. It has been micro-optimized for various of code paths making this, one of, if not the fastest EventEmitter available for Node.js and browsers. The module is API compatible with the EventEmitter that ships by default with Node.js but there are...http://www.npmjs.com/package/eventemitter3
8.JS的EventEmitter使用步骤详解这次给大家带来js的EventEmitter使用步奏详解,使用EventEmitter的注意事项有哪些,下面就是实战案例,一起来看一下。 2个多月前把 Github 上的 eventemitter3 和 Node.js 下的事件模块 events 的源码抄了一遍,才终于对JavaScript事件有所了解。 上个周末花点时间根据之前看源码的理解自己用 ES6 实现了一个 eventemitter...https://www.finclip.com/news/f/85054.html
9.Node.js中的EventEmitter类使用小结node.jsEventEmitter 是Node.js 中的一个核心模块,它提供了一种实现事件驱动编程的机制。它是一个基于观察者模式的类,用于在应用程序中处理事件和触发事件。Node.js 所有的异步 I/O 操作在完成时都会发送一个事件到事件队列。Node.js 里面的许多对象都会分发事件:一个 net.Server 对象会在每次有新连接时触发一个事件, ...https://www.jb51.net/javascript/308041zak.htm
10.Node.js中的EventEmitter模块:基本概念使用方法和常见应用嘲...Node.js是一个基于事件驱动的JavaScript运行时环境,广泛用于服务器端开发。Node.js内置了一个强大的事件模块,称为EventEmitter。EventEmitter提供了一种处理事件和实现自定义事件的能力。 本文将详细介绍Node.js中的EventEmitter模块,包括其基本概念、使用方法和常见应用场景。 https://cloud.tencent.com/developer/article/2300304
11.EventEmitter事件触发器Node 中的很多对象都会触发事件,例如:一个TCP 服务器在收发每个数据流时都触发事件;子进程在退出时 会触发事件。所有能够触发事件的对象都是events.EventEmitter 的实例。 事件命名方式使用大小写分隔的风格。例如:'stream', 'data', 'messageBegin'。 可以将函数注册给对象,使其在事件触发时执行, 此类函数被称作‘...https://www.w3cschool.cn/nodejsdoc/nodejsdoc-753w27ci.html
12.事件与监听返回一个新的EventEmitter。这个EventEmitter没有内置任何事件。 events.observeKey() 启用按键监听,例如音量键、Home键。按键监听使用无障碍服务实现,如果无障碍服务未启用会抛出异常并提示开启。 只有这个函数成功执行后,onKeyDown,onKeyUp等按键事件的监听才有效。 https://www.kancloud.cn/theliang/autojs/2790145
13.eventemitter(opensnewwindow)如果EventEmitter没有为'error'事件注册至少一个监听器,则当'error'事件触发时,会抛出错误、打印堆栈跟踪、且退出 Node.js 进程。 constmyEmitter=newMyEmitter();myEmitter.emit('error',newError('whoops!'));// 抛出错误,并使 Node.js 崩溃 为了防止 Node.js 进程崩溃,可以在使用domain模块。 (注意,domain...https://www.nodeapp.cn/events.html
14.Node.js—Nodev12.16.1(LTS)As this is the first property on EventEmitter that is read-only this feature could be considered Semver-Major. The new feature has been reverted but could re-land in a future Semver-Minor release if a non breaking way of applying it is found....http://nodejs.org/en/blog/release/v12.16.1