使用 js 的 class 类简单的实现一个事件监听机制, 不同于浏览器中的时间绑定与监听, 类似于 node 中的时间监听, 并且会在接下来的文章中去根据自己的理解去写一下 Event 模块中的原理.
Node.js 使用了一个事件驱动, 非阻塞式 I/O 的模型, 使其轻量又高效. 并且 Node 中的大量模块都使用了 Event 机制, 因此可以说是整个 Node 中最重要的模块之一.
实例:
- let event = new eventEmitter();
- event.on('someType',function(){
- });
- event.emit('someType');
依据上述例子, 手动触发一个类型的事件, 调用监听的回调函数, 可以先来实现一个最为简单的小例子, 例如下放代码:
- class eventEmitter {
- constructor() {
- this.callEvent = '';
- }
- on(eventType, callback) {
- this.callEvent = callback;
- };
- emit(eventType) {
- this.callEvent();
- };
- }
- let event = new eventEmitter();
- event.on('click', function () {
- console.log('click')
- });
- event.emit('click');
上述实现的代码, 能够简单的实现, 当我们执行 emit() 方法时, 去执行原本 on() 中传入的回调函数.
我们知道 node 中的 Event 模块是一个简单的事件监听模式的实现. Event 模块中只提供了一个对象 EventEmitter,EventEmitter 的核心就是事件监听与事件触发的监听功能的封装.
EventEmitter 可以让我们注册一个或者多个函数作为 listeners, 在特定的事件触发时被调用. 我们去监听的函数就是 listeners. 当然, 我们可以注册多个监听事件, 所以需要一个 map 结构来存储监听事件和回调函数的对应关系.
在 EventEmitter 类中, 已键值对的方式来存储事件名和对应的监听器.
首先根据上边的类来实现我们 on 事件, 先来个 events 来作为存储的键值对, 每次传入的值为事件类型和回调函数, 代码简单如下:
- EventEmitter.prototype.on = function on(type,listener){
- return _on(this,type,listener);
- };
- function _on(target,type,listener){
- var m;
- var events;
- var existing;
- if(typeof listener !== 'function'){
- throw new Error("监听者必须是一个函数");
- }
- // 获取到对象上的监听事件键值对
- events = target._events;
- if(!events){
- // 如果没有键值对, 则重新自定义
- events = target._events = {};
- target._eventsCount = 0;
- }else{
- // 获取原来键值对中的 listener 事件
- existing = events[type];
- }
- if(!existing) {
- // 如果原本的事件监听的键值对中没有该 type 的该监听事件
- // 则在 events 中存放该 type 和该监听事件的键值对
- existing = events[type] = listener;
- // 并且当前内存中存放的监听事件加 1
- ++target._eventsCount;
- }
- return target;
- }
现在 on 事件可以使用了, 我们先不去思考最大监听数的限制还有键值对的初始化不正确等其他因素, 这些可以放在之后进行优化, 接下来简单的去实现 EventEmitter 中的 emit 事件
- EventEmitter.prototype.emit = function emit(type){
- return _emit(this,type);
- };
- function _emit(target,type){
- var events,exiting,handler;
- if(!type){
- throw new Error('触发的事件不能为空');
- }
- // 获取到对象上的监听事件键值对
- events = target._events;
- // 根据 type 获取到监听事件
- handler = events[type];
- if(!handler){
- return false;
- }
- handler();
- }
同样的 emit 事件的实现是简单的从键值对中根据 type 获取到监听事件去执行. 这里还没有考虑传入多个参数的情况.
根据上边的简单实现, 我们可以来进行下尝试, 比之前的版本相比, 我们可以监听多个事件, 去触发多个回调函数了.
- event.on('click', function () {
- console.log('click')
- });
- event.on('click1',function (){
- console.log('click11');
- });
- event.emit('click');
- // 输出 click
- event.emit('click1');
- // 输出 click11
- console.log(event._events);
- // 输入 {click: [Function],click1:[Function]}
这里简单的实现了多个事件注册, 多个事件触发的 EventEmitter, 接下来会继续进行设置监听个数, 以及触发时传入多个参数的剖析.
参考:[ https://github.com/nodejs/node/blob/v6.0.0/lib/events.js ]
来源: https://www.cnblogs.com/blackgan/p/9005090.html