实现一个EventEmitter (事件触发器)
算是从现在开始自己模仿的第一个轮子把,加油.
要实现一个EventEmitter,核心功能就是实现on
,emit
方法。
on
方法用来为一个事件
绑定一个监听器
1
2
3
4
5
6
7
8
9const a = new EventEmitter()
var listener = function(arg) {
console.log(arg)
}
//第一个参数为事件名称,string类型
//第二个参数为想要绑定的监听器函数,这个函数在这个事件被触发时执行.
a.on("sayHello", listener)
emit
方法用来触发某个事件
,并可以为这个事件所绑定的监听器函数
传入参数。
1 | a.emit("sayHello","hello World") |
构造函数EventEmitter
1 | //eventEmitter.js |
this._event对象存储’事件’与’监听器’的关系,因为每一个事件都可以绑定多个监听器,所以采用数组的形式来存储一个监听队列。结构如上代码注释.
实现on方法
1 | //eventEmitter.js |
如果传入的这个事件的监听队列存在,则直接将其赋值给listeners
变量,若不存在,则给listeners
创建一个新队列(空数组)。
再在listeners
进行操作,将listener添加到监听队列中。
实现emit方法
1 | proto.emit = function(eventName, args) { |
到这里就完成了一个简单的EventEmitter
,后面就是进一步的完善了。
实现off方法
off方法用来移除某个事件的某个监听函数,需要传入参数为,事件名
&监听函数
1
2
3
4
5
6
7
8
9
10
11
12
13proto.off = function(eventName, listener) {
let listeners = this._event[eventName];
//如果事件对应的监听队列不存在,则直接返回
if(!listeners) return;
//采用filter方法将监听队列中监听函数为listener的给筛选掉.
listeners = listeners.filter(e => {
if(e !== listener) return e;
})
return this;
}
实现once方法
once方法对某个特定事件只执行一遍监听函数,执行完毕就将监听函数从监听队列中移除。
1 | /** |
once
方法内部调用on
方法,不过传参的时候多传了个once
参数为ture,所以需要修改on
方法来配合once
方法.
修改后的on方法
1 | proto.on = function(eventName, listener, once = false) { |
变化的地方就是on
方法现在接受三个参数,第三个参数为once,默认值为fasle
。once
方法调用on
方法传过来一个once参数为true
。
现在不直接把监听函数listener
添加到监听队列中,而是用一个对象
来代表一个监听函数,对象的fn字段就是监听函数,once字段代表是否只能够执行一次.
在emit的时候就判断监听队列中的item的once字段是否为true,如果是的话就调用off方法.
添加一个验证listener参数的函数
在调用EventEmitter的各个方法时,如果有需要传一个listener
的参数的话,在内部需要判断这个参数是否为函数,如果不是函数,则抛出一个TypeError.
1 | function isValid(listener) { |
在各个方法需要传入listener参数的就可以添加以下代码进行验证
1 | if(!isValid(listener)) { |
实现Allof方法
1 | /** |
暴露EventEmitter对象1
2
3// eventEmitter.js
module.exports = EventEmitter
Test.js
1 | const eEmitter = require('./eventEmitter'); |
In the End
EventEmitter在Node.js的event模块中,而很多对象都是EventEmitter的实例,他们也就可以使用EventEmitter的方法.
对于EventEmitter
来说,最主要的还是on
和emit
和off
方法,其他的方法都是在这几个的基础上扩展出来的.
通过这次实现,自己也学会了如何把一个任务拆解,并逐渐实现每个小任务,再对最后的结果加以适当的完善。
还有就是需要对整个任务的轮廓有个大概的理解。
呃…还是立个flag吧,实现一个Promise,现在只实现了简单的then
和resolve
。