Thoughts最近在看AsyncJavascript这本书,讲的是JS的异步性,JS事件是解决问题的好方法之一。为了更深入地了解事件的工作原理,我创建了一个自定义EventEmitter,它包含NodeEventEmitter的大部分工作功能。源代码不超过60行。总体思路总体思路是有一个对象(this.handlers)来保存从事件名称(类型:字符串)到其关联的监听器/处理程序(类型:Array)的映射.当每个事件被触发时,遍历关联的侦听器/处理程序并执行它们。classEmitter{constructor(){/***保留映射信息。*例如*{*'event1':[fn1,fn2],*'event2':[fn3,fn4,fn5]*}*/this.handlers={};}}关于方法的一些细节-eventbindingon(evt,handler){this.handlers[evt]=this.handlers[evt]||[];让hdl=this.handlers[evt];hdl.push(处理程序);returnthis;}为简单起见,我们在绑定处理程序时不检查重复项。也就是说,如果你对同一个函数调用了两次,那么当事件触发时,它也会被调用两次。该方法返回this以允许方法链接。off-事件解除绑定移除监听器(evt,处理程序){this.handlers[evt]=this.handlers[evt]||[];让hdl=this.handlers[evt];让索引=hdl.indexOf(处理程序);如果(索引>=0){hdl.splice(索引,1);}returnthis;}注意,这里我们在解绑定函数时比较函数引用和严格比较。Javascript中的函数通过引用进行比较,与对象比较的工作方式相同。functionf1(){console.log('hi');}functionf2(){console.log('hi');}letf3=f1;console.log(f1===f2);//falseconsole.log(f1===f3);//trueonce-绑定,但只能触发一次once(evt,handler){this.handlers[evt]=this.handlers[evt]||[];让hdl=this.handlers[evt];hdl.push(functionf(...args){handler.apply(this,args);this.removeListener(evt,f);});returnthis;}它与on方法类似。但是我们需要用另一个函数包装处理程序,这样我们可以在处理程序执行后删除绑定,以实现仅触发一次。emit-triggereventemit(evt,...args){this.handlers[evt]=this.handlers[evt]||[];让hdl=this.handlers[evt];hdl.forEach((it)=>{it.apply(this,args);});returnthis;}当一个事件被触发时,找到它所有关联的处理程序(即this.handlers[evt])并执行它们。eventNames-获取具有活动(即非空)handlerseventNames()的已注册事件列表{returnObject.keys(this.handlers).reduce((arr,evt)=>{if(this.listenerCount(evt)){arr.push(evt);}returnarr;},[]);}这里我们不'简单地返回this.handlers的所有键,因为一些事件可以与一些处理程序绑定,然后再删除它们。在这种情况下,事件名称作为this.handlers中的有效键存在,但没有活动的处理程序。E.g.letserver=newEmitter();letfn=function(){};server.on('connection',fn);server.removeListener('connection',fn);server.handlers.connection;//[]因此,我们需要过滤掉处理程序为空的事件。这里我们使用Array.prototype.reduce来使代码更简洁一些。在很多情况下reduce都是有用的,例如计算数组的总和:functionsumWithForEach(arr){//withforEachletsum=0;arr.forEach(it=>{sum+=it;})returnsum;}functionsumWithReduce(arr){//使用reducereturnarr.reduce((sum,current)=>{returnsum+current;})}参考AsyncJavascriptNotice如果您受益于此Repo,请「Star」支持。如果您想关注系列阅读笔记的最新消息/文章,请「观看」订阅。