MarsPen / blog

3 stars 0 forks source link

【手写篇 - Day 07】实现一个 Event Emitter #8

Open MarsPen opened 2 years ago

MarsPen commented 2 years ago

题目描述

请实现你自己的 Event Emitter

const emitter = new Emitter()

它需要支持事件订阅

const sub1  = emitter.subscribe('event1', callback1)
const sub2 = emitter.subscribe('event2', callback2)

同一个callback可以重复订阅同一个事件

const sub3 = emitter.subscribe('event1', callback1)
emit(eventName, ...args) //可以用来触发callback
emitter.emit('event1', 1, 2);
// callback1 会被调用两次
subscribe() //返回一个含有release()的对象,可以用来取消订阅。

sub1.release()
sub3.release()
// 现在即使'event1'被触发, 
// callback1 也不会被调用
MarsPen commented 2 years ago

思路

代码

class EventEmitter {
  constructor() {
    this.subs = {};
  }
  subscribe(eventName, callback) {
    this.subs[eventName] ??= new Map();
    const key = Symbol();
    this.subs[eventName].set(key, callback);
    return {
      release: () => {
        this.subs[eventName].delete(key);
      }
    }
  }

  emit(eventName, ...args) {
    for(const callback of this.subs[eventName].values()) {
      try {
        callback(...args);
      } catch (e) {
        console.log(e)
      }
    }
  }
}
MarsPen commented 2 years ago
class EventEmitter {
    constructor () {
        this.subscriptions = new Map()
    }
    subscribe(eventName, callback) {
        if (!this.subscriptions.has(eventName)) {
            this.subscriptions.set(eventName, new Set())
        }
        const subscriptions = this.subscriptions.get(eventName)
        const callbackObj = {callback}
        subscriptions.add(callbackObj)
        return {
            release:()=>{
                subscriptions.delete(callbackObj)
                if (subscriptions.size === 0) {
                    delete this.subscriptions.eventName
                }
            }
        }
    }
    emit(eventName, ...args){
        const subscriptions = this.subscriptions.get(eventName)
        if (subscriptions) {
            subscriptions.forEach((cbObj)=>{
                cbObj.callback.apply(this, args)
            })
        }
    }
}