简单实现
class EventEmitter {
constructor() {
this._event = {}
}
on(name, handler) {
this._event[name] = handler
}
emit(name) {
this._event[name]()
}
}
来解析这段源码
const EventEmitter = require('events');
const myEmitter = new EventEmitter();
myEmitter.on('qweasd', function (a, b) {
console.log(a, b, this === myEmitter);
});
// a b true
myEmitter.emit('qweasd', 'a', 'b');
拆开来看
初始化
const EventEmitter = require('events');
const myEmitter = new EventEmitter();
console.log(myEmitter)
EventEmitter {
_events: [Object: null prototype] {},
_eventsCount: 0,
_maxListeners: undefined,
[Symbol(kCapture)]: false
}
对应源码
function EventEmitter(opts) {
EventEmitter.init.call(this, opts);
}
EventEmitter.init = function(opts) {
if (this._events === undefined ||
this._events === ObjectGetPrototypeOf(this)._events) {
// 创建一个空的对象
this._events = ObjectCreate(null);
this._eventsCount = 0;
}
this._maxListeners = this._maxListeners || undefined;
if (opts?.captureRejections) {
validateBoolean(opts.captureRejections, 'options.captureRejections');
this[kCapture] = Boolean(opts.captureRejections);
} else {
// Assigning the kCapture property directly saves an expensive
// prototype lookup in a very sensitive hot path.
this[kCapture] = EventEmitter.prototype[kCapture];
}
};
module.exports = EventEmitter;
EventEmitter.EventEmitter = EventEmitter;
new EventEmitter() 中 最重要的就是创建了一个 _event 的空对象
module.exports = EventEmitter;
EventEmitter.EventEmitter = EventEmitter;
这两句使得如下两种引用都是可行的
const EventEmitterME = require('events');
const { EventEmitter } = require('events')
const myEmitter = new EventEmitter();
const myEmitterME = new EventEmitterME();
console.log(myEmitter)
console.log(myEmitterME)
注册事件
const EventEmitter = require('events');
const myEmitter = new EventEmitter();
myEmitter.on('qweasd', function (a, b) {
console.log(a, b, this === myEmitter);
});
console.log(myEmitter)
EventEmitter {
_events: [Object: null prototype] { qweasd: [Function (anonymous)] },
_eventsCount: 1,
_maxListeners: undefined,
[Symbol(kCapture)]: false
}
可以看到, 就是给 _events 这个对象上添加一个属性
如果你给同个 EventEmitter 实例添加相同名字的事件, _event 上添加的属性的属性值
是个数组
const EventEmitter = require('events');
const myEmitter = new EventEmitter();
myEmitter.on('qweasd', function (a, b) {
console.log('aaa')
});
myEmitter.on('qweasd', function (a, b) {
console.log('bbb')
});
console.log(myEmitter)
EventEmitter {
_events: [Object: null prototype] {
qweasd: [ [Function (anonymous)], [Function (anonymous)] ]
},
_eventsCount: 1,
_maxListeners: undefined,
[Symbol(kCapture)]: false
}
当注册一个新事件之前, 如果注册了 newListener 事件, 首先会触发 newListener 事件
const EventEmitter = require('events');
const myEmitter = new EventEmitter();
// Only do this once so we don't loop forever
myEmitter.once('newListener', (event, listener) => {
if (event === 'event') {
// Insert a new listener in front
myEmitter.on('event', () => {
console.log('B');
});
}
});
myEmitter.on('event', () => {
console.log('A');
});
myEmitter.emit('event');
B
A
on 就是调用 addListener 函数
源码如下, 核心代码就是 if (existing === undefined) 下的 events[type] = listener; (event 就是 _events) 将 listener 添加到 _event 这个对象上
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
EventEmitter.prototype.addListener = function addListener(type, listener) {
return _addListener(this, type, listener, false);
};
function _addListener(target, type, listener, prepend) {
let m;
let events;
let existing;
checkListener(listener);
events = target._events;
if (events === undefined) {
events = target._events = ObjectCreate(null);
target._eventsCount = 0;
} else {
// To avoid recursion in the case that type === "newListener"! Before
// adding it to the listeners, first emit "newListener".
if (events.newListener !== undefined) {
target.emit('newListener', type,
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.
// 给对应的 events, 即 target._events 添加注册的 listener
events[type] = listener;
++target._eventsCount;
} else {
if (typeof existing === 'function') {
// Adding the second element, need to change to array.
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
m = _getMaxListeners(target);
if (m > 0 && existing.length > m && !existing.warned) {
existing.warned = true;
// No error code for this since it is a Warning
// eslint-disable-next-line no-restricted-syntax
const w = new Error('Possible EventEmitter memory leak detected. ' +
`${existing.length} ${String(type)} listeners ` +
`added to ${inspect(target, { depth: -1 })}. Use ` +
'emitter.setMaxListeners() to increase limit');
w.name = 'MaxListenersExceededWarning';
w.emitter = target;
w.type = type;
w.count = existing.length;
process.emitWarning(w);
}
}
return target;
}
触发事件
可以看到, emit 就是触发 _event 对象上对应某个 type 的特定的函数
EventEmitter.prototype.emit = function emit(type, ...args) {
let doError = (type === 'error');
const events = this._events;
if (events !== undefined) {
if (doError && events[kErrorMonitor] !== undefined)
this.emit(kErrorMonitor, ...args);
doError = (doError && events.error === undefined);
} else if (!doError)
return false;
// If there is no 'error' event listener then throw.
if (doError) {
let er;
if (args.length > 0)
er = args[0];
if (er instanceof Error) {
try {
const capture = {};
ErrorCaptureStackTrace(capture, EventEmitter.prototype.emit);
ObjectDefineProperty(er, kEnhanceStackBeforeInspector, {
value: FunctionPrototypeBind(enhanceStackTrace, this, er, capture),
configurable: true
});
} catch {}
// Note: The comments on the `throw` lines are intentional, they show
// up in Node's output if this results in an unhandled exception.
throw er; // Unhandled 'error' event
}
let stringifiedEr;
try {
stringifiedEr = inspect(er);
} catch {
stringifiedEr = er;
}
// At least give some kind of context to the user
const err = new ERR_UNHANDLED_ERROR(stringifiedEr);
err.context = er;
throw err; // Unhandled 'error' event
}
const handler = events[type];
if (handler === undefined)
return false;
if (typeof handler === 'function') {
// 触发 _event 对象上对应某个 type 的特定的函数
const result = handler.apply(this, args);
// We check if result is undefined first because that
// is the most common case so we do not pay any perf
// penalty
if (result !== undefined && result !== null) {
addCatch(this, result, type, args);
}
} else {
const len = handler.length;
const listeners = arrayClone(handler);
for (let i = 0; i < len; ++i) {
const result = listeners[i].apply(this, args);
// We check if result is undefined first because that
// is the most common case so we do not pay any perf
// penalty.
// This code is duplicated because extracting it away
// would make it non-inlineable.
if (result !== undefined && result !== null) {
addCatch(this, result, type, args);
}
}
}
return true;
};