前言
EventEmitter
可以提供我们实现事件的发布和订阅。
Node.js
已经提供了封装好的 EventEmitter
供我们使用,通过 events
模块可以使用。
1
| const eventEmitter = require('events').EventEmitter;
|
然而,自己动手实现 Wheel
(造轮子)虽然不能够做到已有库那般稳定、高性能,但是有利于我们去了解其内部机理。
下面我们自己实现了一个简易的EventEmitter。
准备工作
这里我是通过 JavaScript
语言实现的,利用到了少量 ES6
标准中的新内置变量。因此,希望你对这俩有一些基础的了解和基本应用能力。
(这里我推荐阮一峰老师的教程)
实现原理
EventEmitter
的实现原理还是比较简单的,用一句话概括就是:基于事件名称存储对应的方法,并通过事件名称调用方法。
其实,但凡关于事件的订阅与发布,其最基本原理皆是如此,不过是实现方法的差异而已。
因为我们需要重新造轮子,所以我们根据上述原理,可以把实现流程概括如下:
- 创建存储所有事件及方法的字典
events
{}
- 发布事件时,提供事件名称
eventName
和方法 func
,并添加到 events
中。
- 触发事件时,提供事件名称
eventName
和方法参数 args
,在 events
中找到对应方法并执行。
- 卸载事件时,提供事件名称
eventName
和方法 func
,在 events
中找到对应内容进行删除。
实现代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
| export const EventEmitter = new class EventEmitter{ constructor(){ this.events = {} }
static VERSION = '1.0.0'
isFunction = (func) => { if (typeof func === 'function') { return true } else if (typeof func === 'object') { return this.isFunction(func.func) } else { return false } }
on = (eventName, func) => { try{ if(!eventName || !func) throw new Error('Please ensure that the parameters are complete !'); if(!this.isFunction(func)) throw new Error('The second parameter must be a function or an Object with func!'); (this.events[eventName] || (this.events[eventName] = [])).push( typeof func === 'object' ? func : { func: func, once: false }); } catch(err){ console.log(err) } return this; }
once = (eventName, func) => { return this.on(eventName, { func: func, once: true }) }
off = (eventName, func) => { if(!eventName || !this.events[eventName]) return this; if(!func){ this.clear(eventName) }else{ const funcs = this.events[eventName]; for(let i = 0; i < funcs.length; i++){ if(funcs[i].func === func){ funcs.splice(i, 1) } } if(funcs.length === 0){ this.clear(eventName) } } return this;
}
clear = (eventName) => { if(eventName && this.events[eventName]){ Reflect.defineProperty(this.events, eventName) }else{ this.events = {} } }
emit = (eventName, ...args) => { try{ const funcs = this.events[eventName]; if(!funcs) throw new Error(eventName, 'is not existed');; funcs.forEach(element => { element.func.call(this, ...args); if (element.once) { this.off(eventName, element.func) } }); }catch(err){ console.log(err); } return this; } }()
|
基础功能
on
添加一个事件并发布。
1
| eventEmitter.on(eventName, func)
|
emit
触发某个事件。
1
| eventEmitter.emit(eventName, ...args)
|
- eventName 事件名称
- args 监听函数的形参
off
删除已发布的一个事件。
1
| eventEmitter.off(eventName, func)
|
once
添加一个只能触发一次的事件,执行后将自动被删除。
1
| eventEmitter.once(eventName, func)
|
clear
清除一个事件或所有事件。
1
| eventEmitter.clear(eventName)
|
使用案例
导入
1
| import { eventEmitter } from 'path/EventEmitter.js';
|
或
1
| <script src='path/eventEmitter.js'></script>
|
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| eventEmitter.on('sayHello', (name) => { console.log('Hello! ' + name.toString() + '!') });
const Name = 'Douchen'; eventEmitter.emit('sayHello', Name);
eventEmitter.once('sayBye', (name) => { console.log('ByeBye! ' + name.toString() + '!') });
eventEmitter.emit('sayBye', Name); eventEmitter.emit('sayBye', 'Superman');
eventEmitter.off('sayHello', (name) => { console.log('ByeBye! ' + name.toString() + '!') }); console.log(eventEmitter.events);
eventEmitter.on('planA', () => { console.log('This is planA'); }); eventEmitter.on('planB', () => { console.log('This is planB'); }); eventEmitter.on('planC', () => { console.log('This is planC'); });
eventEmitter.clear('planA'); console.log(eventEmitter.events);
eventEmitter.clear(); console.log(eventEmitter.events);
|
很感谢你能看到这里!谢谢~
博主已经将源码文件上传到了 Github 中,如有需要请自取 👉 EventEmitter
参考资料: (衷心感谢各参考资料提供的帮助)