仿照events实现个发布订阅模式的EventEmitter。
addListener注册event,保存进map。只注册一个event时,回调函数作为function型对象直接存进map。注册多个同名event时,回调函数作为Array型存进map。
removeListener撤销从map中撤销已注册的event。如果只注册了一次,直接从map中删除。如果注册了多次,从回调函数的Array中删除相应的回调函数。
emit触发event。
class EventEmitter { constructor() { this._events = this._events || new Map(); } emit(type, ...args) { let handler = this._events.get(type); // 从 this._events 中获取事件的回调函数 if (Array.isArray(handler)) { // 数组表示有多个listener,需要依次触发回调函数 for (let i = 0; i < handler.length; i++) { if (args.length > 0) { handler[i].apply(this, args); } else { handler[i].call(this); } } } else { if (args.length > 0) { handler.apply(this, args); } else { handler.call(this); } } return true; }; addListener(type, fn) { const handler = this._events.get(type); if (!handler) { // 将事件与回调函数保存到 this._events this._events.set(type, fn); } else if (typeof handler === 'function') { // 如果 handler 是函数,说明目前只有一个监听者,现在要让 handler 变成数组 this._events.set(type, [handler, fn]); } else if (Array.isArray(handler)) { // 如果 handler 是数组,说明已经有多个监听者,只要简单 push 进数组即可 handler.push(fn); } } removeListener(type, fn) { const handler = this._events.get(type); if (!handler) { return null; } else if (typeof handler === 'function') { // 如果 handler 是函数,说明目前只有一个监听者,直接删除 this._events.delete(type, fn); } else if (Array.isArray(handler)) { // 如果 handler 是数组,说明已经有多个监听者,移除相应的监听者 let position = -1; handler.forEach((item, index) => { if (item === fn) { position = index; } }); if (position === -1) { return null; } handler.splice(position, 1); // 如果清除后,数组内只有一个函数,那就取消数组,以函数形式保存 if (handler.length === 1) { this._events.set(type, handler[0]); } } } } module.exports = EventEmitter;
测试:
const EventEmitter = require( './eventEmitter.js'); const emitter = new EventEmitter(); function callback1(name) { console.log(`I am ${name}`); } function callback2(name) { console.log(`${name} is fool`); } function callback3(name) { console.log(`${name} is clever`); } emitter.addListener('person', callback1); emitter.addListener('person', callback2); emitter.addListener('person', callback3); emitter.removeListener('person', callback2); emitter.emit('person', 'icon man');
太粗糙了,参数也没校验,异常也没处理,once/removeAllListeners也没实现。