EventEmitter简介
EventEmitter是Node.js的内置模块events提供的一个类,它是Node事件流的核心,EventEmitter是服务端的东西, 
前端已经有event-emitter的npm库 地址: https://www.npmjs.com/package/event-emitter 
<https://www.npmjs.com/package/event-emitter>   
高级浏览器也有原生提供的EventTarget这种实现事件监听和触发的API 地址: 
https://developer.mozilla.org/zh-CN/docs/Web/API/EventTarget 
<https://developer.mozilla.org/zh-CN/docs/Web/API/EventTarget>   
但是它们和Node.js的事件API都有或多或少的区别,今天我们就来实现一个前端版本的EventEmitter 我本章demo的github地址如下 
https://github.com/penghuwan/event-emitter 
<https://github.com/penghuwan/event-emitter>   
API介绍 
我们要实现的API有: 
 * on(event, listener):为指定事件注册一个监听器,接受一个字符串 event 和一个回调函数。 
 * emit(event, [arg1], [arg2]): 按监听器的顺序执行执行每个监听器 
 * addListener(event, listener):on的同名函数(alias) 
 * once(event, listener): 和on类似,但只触发一次,随后便解除事件监听 
 * removeListener(event, listener): 移除指定事件的某个监听回调 
 * removeAllListeners([event]):移除指定事件的所有监听回调 
 * setMaxListeners(n):用于提高监听器的默认限制的数量。(默认10监听回调个产生警告) 
 * listeners(event): 返回指定事件的监听器数组。 为了保证兼容性和简单性,下面的编码全部基于ES5语法实现   
构造函数
首先我们需要写一个EventEmitter构造函数,给它设置两个属性listeners和maxListener function 
EventEmitter() {this.listeners = {}; this.maxListener = 10; } 
listeners用于存放事件监听器函数,结构如下:
{ "event1": [f1,f2,f3], "event2": [f4,f5], ... } 
而maxListener 是设置的某个事件能够添加的监听器的最大数量
,超过这个值,需要在控制台输出警告,但不会报错阻止。按照Node的设计,这个值能够通过setMaxListeners动态调整
on方法
 * 判断该事件的监听器数量是否已超限,超限则报警告 
 * 判断该事件监听器数组是否初始化,若未初始化,则将listeners[event]初始化为数组,并加入监听器cb 
 * 若监听器数组已经被初始化,则判断数组中是否已存在cb,不存在则添加,已存在则不做操作。 
 * 指定addListener等于on方法 EventEmitter.prototype.on = function (event, cb) { var 
listeners =this.listeners; if (listeners[event] && listeners[event].length >= 
this.maxListener) { throw console.error('监听器的最大数量是%d,您已超出限制', this.maxListener) 
}if (listeners[event] instanceof Array) { if (listeners[event].indexOf(cb) === 
-1) { listeners[event].push(cb); } } else { listeners[event] = [].concat(cb); } 
} EventEmitter.prototype.addListener= EventEmitter.prototype.on; 
emit方法
 * 
通过Array.prototype.slice.call(arguments)取出方法的参数列表args,(因为考虑简单性和兼容性所以采用ES5的冗长编码方式)
 * 调用args.shift踢掉数组第一个参数即event,留下来的这些是要传给监听器的 
 * 遍历监听器,通过apply方法把上面得到的args参数传进去 EventEmitter.prototype.emit = function 
(event) {var args = Array.prototype.slice.call(arguments); args.shift(); this
.listeners[event].forEach(cb => { cb.apply(null, args); }); } 
 
removeListener方法
 * 通过indexOf确定监听器回调在数组listeners[event]中的位置 
 * 通过splice(i,1)删除之 EventEmitter.prototype.removeListener = function (event, 
listener) {var listeners = this.listeners; var arr = listeners[event] || []; var
 i = arr.indexOf(listener); if (i >= 0) { listeners[event].splice(i, 1); } } 
once方法
once方法是on方法和removeListener方法的结合:用on方法监听,在回调结束的最后位置,通过removeListener删掉监听函数自身 
EventEmitter.prototype.once =function (event, listener) { var self = this; 
function fn() { var args = Array.prototype.slice.call(arguments); 
listener.apply(null, args); self.removeListener(event, fn); } this.on(event, 
fn) } 
removeAllListener方法
清空listeners[event]数组 EventEmitter.prototype.removeAllListener = function 
(event) {this.listeners[event] = []; } 
setMaxListeners方法和listeners方法
EventEmitter.prototype.listeners = function (event) { return this
.listeners[event]; } EventEmitter.prototype.setMaxListeners= function (num) { 
this.maxListener = num; } 
 
Github地址
https://github.com/penghuwan/event-emitter 
<https://github.com/penghuwan/event-emitter>
热门工具 换一换