Skip to content

手写一个发布-订阅模式 #110

Open

Description

@sisterAn
class EventEmitter {
  constructor() {
    // 初始值为空对象
    this.listeners = Object.create(null)
  }
  
  // 注册事件
  on = (event, listener) => {
    // this.bindEvent(event, listener, false)
    if (!event || !listener) {
      return
    }
    if (this.listeners[event]) {
        //如果有就放一个新的
        this.listeners[event].push(listener)
    } else {
        //如果没有就创建一个数组
        this.listeners[event] = [listener]
    }
  }
  
  // 只订阅一次
  once = (event, listener) => {
    // this.bindEvent(event, listener, true)
    function one() {
        // 在one函数运行原来的函数,只有将one清空
        listener.apply(this, arguments)
        // 先绑定 执行后再删除
        this.off(event)
    }
      this.on(event, one)
      //此时emit触发会执行此函数,会给这个函数传递rest参数
  }
  
  // 发布事件
  emit = (event, ...args) => {
    if (!this.hasBind(event)) {
      console.warn(`this event: ${event} don't has bind listener.`)
      return
    }

    this.listeners[event].forEach(listener => listener.call(this, ...args))
  }
  
  // 取消订阅
  off = (event, listener) => {
    if (!this.hasBind(event)) {
      console.warn(`this event: ${event} don't exist.`)
      return
    }

    // remove all listener
    if (!listener) {
      delete this.listeners[event]
      return
    }

    // remove specific listener
    this.listeners[event] = this.listeners[event].filter(item => item !== listener)
  }

  hasBind = event => {
    return this.listeners[event]
      && this.listeners[event].length
  }
}

// 测试
const baseEvent = new EventEmitter()
function cb(value){
    console.log("hello "+value)
}
baseEvent.once("click",cb)
// baseEvent.off("click")
baseEvent.emit("click",'2020')
// hello 2020
console.log(baseEvent.listeners)

Activity

  1. chenguzhen87 commented on Nov 11, 2020

    @chenguzhen87

    因该要加一个逻辑,不然该事件清除了,又调用解绑事件
    if (this.listeners[event]) {
    this.off(event)
    }

  2. omitchen commented on Dec 9, 2020

    @omitchen
    this.off(event)
    

    执行一次把前面所有订阅的事件都卸载了,不太合适吧

  3. xllpiupiu commented on Oct 7, 2021

    @xllpiupiu
    /**
     * https://blog.csdn.net/weixin_43792004/article/details/113442506
     */
    //中间人 主题
    class Dep {
        constructor(callback) {
            this.subs = []
            this.callback = callback
        }
        addSub(sub) {
            this.subs.push(sub)
            return this
        }
        notify() {
            this.subs.forEach(item=>item.update(this.callback))
        }
    }
    //订阅者
    class Sub {
        constructor(val) {
            this.val = val
        }
        update(callback) {
            this.val = callback(this.val);
            console.log('this.val: ', this.val);
        }
    }
    //发布者
    class Pub {
        constructor() {
            this.deps = []
        }
        addDep(dep) {
            this.deps.push(dep)
        }
        removeDep(dep) {
            let index = this.deps.indexOf(dep)
            if(index!==-1) {
                this.deps.splice(index,1)
                return true
            }
            return false
        }
        publish(dep) {
            this.deps.forEach(item=>item===dep&&item.notify())
        }
    }
    let dep1 = new Dep(item=>item*item)
    let sub1 = new Sub(3)
    dep1.addSub(sub1)
    let pub1 = new Pub()
    pub1.addDep(dep1)
    pub1.publish(dep1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions