blog
blog copied to clipboard
events实现原理
function checkListener(listener) {
if (typeof listener !== 'function') {
throw new Error('listener', 'Function', listener);
}
}
function spliceOne(list, index) {
for (; index + 1 < list.length; index++)
list[index] = list[index + 1];
list.pop();
}
function EventEmitter() {
EventEmitter.init.call(this)
}
EventEmitter.prototype._events = undefined
EventEmitter.prototype._eventsCount = 0;
EventEmitter.prototype._maxListeners = undefined
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;
}
function _addListener(target, type, listener) {
let events;
let exiting;
checkListener(listener)
events = target._events
if (events === undefined) {
events = target._events = Object.create(null)
target._eventsCount = 0;
} else {
exiting = events[type]
}
if (exiting === undefined) {
// { add: fn }
events[type] = listener;
++target._eventsCount;
} else {
// { add: [fn, fn] }
if (typeof exiting === 'function') {
exiting = events[type] = [exiting, listener]
} else {
exiting.push(listener)
}
}
console.log(events)
return target
}
EventEmitter.prototype.addListener = function addListener(type, listener) {
return _addListener(this, type, listener)
}
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
EventEmitter.prototype.removeListener = function removeListener (type, listener) {
let list;
let events;
checkListener(listener)
events = this._events;
if (events === undefined) {
return this;
}
list = events[type]
if (list === undefined) {
return this;
}
if (list === listener || list.listener === listener) {
if (--this._eventsCount === 0) {
// 如果只有一个直接清空
this._events = Object.create(null)
} else {
// 删除当前的那个
delete events[type];
}
}
}
EventEmitter.prototype.of = EventEmitter.prototype.removeListener
EventEmitter.prototype.emit = function emit(type, ...args) {
const events = this._events;
const handler = events[type]
if (handler === undefined) {
return false;
}
if (typeof handler === 'function') {
Reflect.apply(handler, this, args)
} else {
const len = handler.length;
const listeners = arrayClone(handler, len);
for (let i = 0; i < len; i++) {
Reflect.apply(listeners[i], this, args)
}
}
return true
}
function arrayClone(arr, n) {
var copy = new Array(n);
for (var i = 0; i < n; ++i)
copy[i] = arr[i];
return copy;
}
function _onceWrap(target, type, listener) {
let state = { fired: false, wrapFn: undefined, target, type, listener }
var wrapped = onceWrapper.bind(state);
// 给绑定之后的函数增加属性listener
wrapped.listener = listener;
state.wrapFn = wrapped;
return wrapped
}
function onceWrapper(...args) {
// once只是用函数包了一次里面通过一个标识符控制的
if (!this.fired) {
this.target.removeListener(this.type, this.wrapFn);
this.fired = true;
Reflect.apply(this.listener, this.target, args)
}
}
EventEmitter.prototype.once = function once(type, listener) {
checkListener(listener)
this.on(type, _onceWrap(this, type, listener))
return this
}
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.once('event', () => {
console.log('once');
});
myEmitter.emit('event');
// 打印: once
myEmitter.emit('event');
// 不触发