Emitter
by Paco86
HTML
<!-- const emitter = new Emitter();
1.support subscribing to events.
const sub = emitter.subscribe('event_name', callback);
2. support emitting events
It should lead to the callback being invoked with foo and bar as parameters
emitter.emit('event_name', 'foo', 'bar');
3. support unubscribing exixting subscriptions by releasing them
sub.release();
如果一个函数被 subscribe 多次,如何根据返回的 subscription,delete 的时候删除特定的函数,而不是两个相同的函数随便删除一个。
几个follow up:
因为我一开始是把subscribe后返回的东西直接先定义一个class再new:
面试官问What if we don’t want to use another class object? 考察了稍微进阶一点的prototype用法,另一篇面经里有
What if the callback() function throws error? What will happen? (w/o using try...catch) 这题有点摸不清面试官要问啥,到底是问怎么更好的handle error,还是考察error发生后对app有什么影响。当时东扯西扯反正把我知道的都讲出来了,但自己感觉答的有点不organize -->
JavaScript
class Emitter {
constructor() {
// listeners to save even with callbacks
this.listeners = new Map();
}
subscribe = (eventName, callback) => {
if (this.listeners.has(eventName)) {
var eventMap = this.listeners.get(eventName);
eventMap.set(callback, (eventMap.get(callback) || 0) + 1);
} else {
this.listeners.set(eventName, new Map().set(callback, 1));
}
return {
release: () => {
if (this.listeners.has(eventName)) {
// only release one callback in 0(1)
var eventList = this.listeners.get(eventName);
var frequency = eventList.get(callback) - 1;
if (frequency === 0) {
eventList.delete(callback);
} else {
eventList.set(callback, frequency);
}
//if empty, delete the listener
if (eventList.size === 0) this.listeners.delete(eventName);
}
}
}
}
emit = (eventName, ...args) => {
const listeners = this.listeners.get(eventName);
if (listeners) {
listeners.forEach((frequency, callback) => {
try {
callback.apply(this, args);
} catch(err) {
console.log(err);
}
});
} else {
/* throw new Error('No emitter!'); */
console.log(`You are not subscribed to ${eventName}`)
}
}
}
var cbFn = (a, b) => {console.log(a, b);};
const emitter = new Emitter();
const suba1 = emitter.subscribe('aaa', cbFn);
const suba2 = emitter.subscribe('aaa', cbFn);
/* const suba1 = emitter.subscribe('aaa', function cb1(a, b) {
console.log(a, b);
});
const suba2 = emitter.subscribe('bbb', function cb2(a, b) {
console.log(a + b);
}); */
/* const sub2 = emitter.subscribe('bbb', (a, b, c) => {
console.log(a, b, c);
}); */
emitter.emit('aaa', 'foo', 'bar');
suba1.release()
emitter.emit('aaa', 'foo', 'bar');
/* suba1.release();
suba2.release(); */
/* suba1.release();
emitter.emit('aaa', 'foo',...