subscribe(event, callback) { if (typeof event !== 'string') { thrownewError('Event name must be a string'); } if (typeof callback !== 'function') { thrownewError('Callback must be a function'); } if (!this.events[event]) { this.events[event] = []; } this.events[event].push(callback); }
unsubscribe(event, callback) { if (typeof event !== 'string') { thrownewError('Event name must be a string'); } if (typeof callback !== 'function') { thrownewError('Callback must be a function'); } if (!this.events[event]) return; this.events[event] = this.events[event].filter(cb => cb !== callback); }
publish(event, data) { if (typeof event !== 'string') { thrownewError('Event name must be a string'); } if (!this.events[event]) return; this.events[event].forEach(callback =>callback(data)); } }
开发中我们会遇到一些一次性事件,不会被触发第二次了,我们可以加一个参数来省去手动清除事件的负担:
1 2 3 4 5 6 7 8
publish(event, data, once = false) { if (typeof event !== 'string') { thrownewError('Event name must be a string'); } if (!this.events[event]) return; this.events[event].forEach(callback =>callback(data)); if(once) deletethis.events[event]; }
如果一个回调函数在被调用时订阅了相同的事件,可能会导致无限循环。这是因为publish方法会立即调用所有的回调函数,而这些回调函数可能会改变监听器列表。 上面的代码并没有考虑这个问题,但测试后发现并不会发生无限循环的情况,这是什么原因呢?问题出在 for 和 forEach 中,forEach 方法在开始循环时就已经确定了循环的次数,所以,即使在回调函数中添加或删除了元素,也不会影响forEach的循环次数;而 for 循环会实时检查数组的长度,故而会出现上述的情况。