events.js 源码分析
events.js 源码分析
1. 初始化
// 使用
this.ee = new EventEmitter();
// 源码
// 绑定this域,初始化 _events,_eventsCount和_maxListeners对象
function EventEmitter() {
EventEmitter.init.call(this);
}
EventEmitter.init = function() {
if (
this._events === undefined ||
this._events === Object.getPrototypeOf(this)._events
) {
this._events = Object.create(null);
this._eventsCount = 0;
}
this._maxListeners = this._maxListeners || undefined;
};
2.注册监听事件
// 使用
this.ee.on("message", function(text) {
console.log(text);
that.setState({
text: text
});
});
// 调用的是addListener
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
EventEmitter.prototype.addListener = function addListener(type, listener) {
// 注意最后一个参数为false
return _addListener(this, type, listener, false);
};
function _addListener(target, type, listener, prepend) {
var m;
var events;
var existing;
// 判断是否是方法
if (typeof listener !== "function") {
throw ...
}
// this._events为单个EventEmitter对象中,注册事件的总对象,例如:{login:funcation(){xxxx},loginOut:funcation(){}}
events = target._events;
if (events === undefined) {
events = target._events = Object.create(null);
target._eventsCount = 0;
} else {
// To avoid recursion in the case that type === "newListener"! Before
// adding it to the listeners, first emit "newListener".
// 在添加监听时,判断是否有注册type='newListener'的监听,有的话,每_addListener便调用
// newListener
if (events.newListener !== undefined) {
target.emit(
"newListener",
type,
listener.listener ? listener.listener : listener
);
// Re-assign `events` because a newListener handler could have caused the
// this._events to be assigned to a new object
events = target._events;
}
// 获取是否已经注册过了
existing = events[type];
}
if (existing === undefined) {
// Optimize the case of one listener. Don't need the extra array object.
// 没有注册过,赋值
existing = events[type] = listener;
++target._eventsCount;
} else {
if (typeof existing === "function") {
// Adding the second element, need to change to array.
// 如果有相同的type,则将 新,旧listener封装成数组,并且根据prepend
// 决定先后执行顺序
existing = events[type] = prepend
? [listener, existing]
: [existing, listener];
// If we've already got an array, just append.
} else if (prepend) {
existing.unshift(listener);
} else {
existing.push(listener);
}
// Check for listener leak
// 检查listener是否超过最大值,m初始化为10
m = $getMaxListeners(target);
if (m > 0 && existing.length > m && !existing.warned) {
...
}
}
return target;
}
-
获取
EventEmitter
对象events = target._events;
-
events == null
进行判断- true: 初始化
events = target._events = Object.create(null); target._eventsCount = 0;
- false:
- 判断是否存在
newListener
- 存在: 调用
target.emit("newListener",xxxx)
- 存在: 调用
existing = events[type];
获取缓存数据,没有为undefined
- 判断是否存在
- true: 初始化
-
判断
existing === undefined
-
true: 赋值
existing = events[type] = listener;
++target._eventsCount;
相当于给EventEmitter赋值
{xxxx,'type':listener}
-
false: 意味着注册了相同的type,将会生成
{xxxx,'type':[listener1,listener2]}
类似对象.ps:
prepend == true
的时候,新listener
,将会排列在数组的最前面.
-
-
检查listener是否超过最大值,初始化为10
-
返回
target
也就是当前EventEmitter
对象.
3.发送事件
// 使用
this.ee.emit("message", "hello world 按钮1");
EventEmitter.prototype.emit = function emit(type) {
var args = [];
// 获取除了type之外的参数,也就是传递参数
for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);
var doError = type === "error";
// this._events为单个EventEmitter对象中,注册事件的总对象,例如:{login:funcation(){xxxx},loginOut:funcation(){}}
var events = this._events;
// 进行error判断 暂时不关注
...
// 获取到type对应的执行函数listener
var handler = events[type];
// 没有执行函数 return
if (handler === undefined) return false;
// 根据是funcation还是数组,分别执行对应的调用函数方法
if (typeof handler === "function") {
ReflectApply(handler, this, args);
} else {
var len = handler.length;
var listeners = arrayClone(handler, len);
for (var i = 0; i < len; ++i) ReflectApply(listeners[i], this, args);
}
return true;
};
// 兼容处理
var ReflectApply =
R && typeof R.apply === "function"
? R.apply
: function ReflectApply(target, receiver, args) {
return Function.prototype.apply.call(target, receiver, args);
};
- 通过
arguments
获取到除type
外其他的传入参数,用于最后调用方法时传递给执行函数 - 错误处理
- 获取到
handler
,并判断是否为undefined
- 根据获取到的
handler
,判断是funcation
还是数组
,分别执行对应的调用函数方法.
4.once解析
// 使用
// 注册
this.ee.once("message3", function(text) {
alert(text);
});
// 发送
this.ee.emit("message3", "按钮3,只调用一次this.ee.once");
EventEmitter.prototype.once = function once(type, listener) {
if (typeof listener !== "function") {
throw ....
}
// 包装 listener
this.on(type, _onceWrap(this, type, listener));
return this;
};
function _onceWrap(target, type, listener) {
var state = {
fired: false,
wrapFn: undefined,
target: target,
type: type,
listener: listener
};
// 将onceWrapper的this绑定为上面创建的state对象
var wrapped = onceWrapper.bind(state);
wrapped.listener = listener;
state.wrapFn = wrapped;
return wrapped;
}
function onceWrapper() {
var args = [];
for (var i = 0; i < arguments.length; i++) args.push(arguments[i]);
if (!this.fired) {
// 判断是否使用过,没使用过的话先删除type--onceWrapper
this.target.removeListener(this.type, this.wrapFn);
this.fired = true;
// 执行listener,并且传递数据
ReflectApply(this.listener, this.target, args);
}
}
-
包装执行函数
listener
-
创建
state
对象,将onceWrapper
的this
绑定为state
-
调用发送事件
emit
后调用到onceWrapper
方法,先删除EventEmitter
对应的type:onceWrapper
,然后执行
state
中的listener
-
再次发送事件则在
EventEmitter
找不到对应的type
,实现了只能监听一次.