JavaScript-Algorithms icon indicating copy to clipboard operation
JavaScript-Algorithms copied to clipboard

手写一个发布-订阅模式

Open sisterAn opened this issue 3 years ago • 3 comments

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)

sisterAn avatar Sep 21 '20 00:09 sisterAn

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

chenguzhen87 avatar Nov 11 '20 10:11 chenguzhen87

this.off(event)

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

omitchen avatar Dec 09 '20 03:12 omitchen

/**
 * 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)

xllpiupiu avatar Oct 07 '21 06:10 xllpiupiu