【12-21】Vue中的观察者模式和订阅——发布模式

订阅——发布模式

  • Vue 中使用 $on$emit 一般用来使用兄弟组件中的参数传递,其原理就是使用了订阅发布模式

Vue 的例子




  
  
  Vue 中发布订阅模式


  
  



使用 JavaScript 模拟订阅发布

function EventElement2 () {
  this.subs = {}
}

EventElement2.prototype.$on = function(event, fn) {
    // 如果有值就直接赋值,如果为空赋值 [] 
  this.subs[event] = this.subs[event] || []
  // 存储事件
  this.subs[event].push(fn)
}
EventElement2.prototype.$emit = function(event, params) {
  // 判断事件是否存在,存在去执行相应的事件
  if (this.subs[event]) {
    this.subs[event].forEach((fn) => {
      fn(params)
    })
  }
}

let em2 = new EventElement2
em2.$on('click', (val) => {
  console.log('click2 ---->', val)
})

em2.$emit('click', 'hello')

使用 ES6 的方式实现

// 事件触发器
class EventElement {
  constructor() {
    // this.subs = {}
    this.subs = Object.create(null) // 这样写性能会好一点
  }
  // 注册事件
  $on(event, fn) {
    // 如果有值就直接赋值,如果为空赋值 [] 
    this.subs[event] = this.subs[event] || []
    // 存储事件
    this.subs[event].push(fn)
  }
  // 触发事件
  $emit(event, params) {
    // 判断时间是否存在,存在去执行相应的事件
    if (this.subs[event]) {
      this.subs[event].forEach((fn) => {
        fn(params)
      })
    }
  }
}

let em = new EventElement
em.$on('click', (val) => {
  console.log('click1 ---->', val)
})

em.$emit('click', 'hello')


class Publisher{
    constructor(){
        this.subMap={}
    }
    subscribe(type,cb){
        if(this.subMap[type]){
            if(!this.subMap[type].includes(cb)){
                this.subMap[type].push(cb)
            }
        }else{
            this.subMap[type]=[cb]
        }
    }
    unsubscribe(type,cb){
        if(this.subMap[type]&&this.subMap[type].includes(cb)){
            console.log('cancel');
            console.log(this.subMap[type]);
            const index = this.subMap[type].indexOf(cb);
            this.subMap[type].splice(index,1)
            console.log(this.subMap[type]);
        }
    }
    notify(type,args){
        if(this.subMap[type]){
            this.subMap[type].forEach(cb=>{
                cb(args)
            })
        }
    }
}
let pub = new Publisher()
pub.subscribe('公众号1', fn1 = msg => console.log(`孙悟空订阅的公众号1: ${msg}`));
pub.subscribe('公众号1', fn2 = msg => console.log(`猪八戒订阅的公众号1: ${msg}`));
pub.unsubscribe('公众号1', fn2);  
pub.notify('公众号1', '今天我们的粉丝查过100万啦!!!');

观察者模式和订阅发布模式的区别

观察者模式是由具体的目标调用,例如:当事件触发 Dep 就会去调用观察者的方法,所以订阅者和观察者之间是存在依赖的。
发布订阅模式是由统一的调度中心调用,因为发布者和订阅者不需要知道对方的存在。

观察者模式

贴一个 Vue 中源码的观察者模式源码

【12-21】Vue中的观察者模式和订阅——发布模式_第1张图片
image

手动实现观察者模式

// 发布者-目标
class Dep {
  constructor() {
    // 记录所有的订阅者
    this.subs = []
  }
  // 添加订阅者
  addSub(sub) {
    // 判断订阅者是否存在,并且有update 方法
    if (sub && sub.update) {
      this.subs.push(sub)
    }
  }
  // 发布通知
  notify() {
    // 循环发布通知
    this.subs.forEach(s => {
      s.update()
    })
  }
}

// 订阅者-观察者
class Watcher {
  update() {
    console.log('update --->')
  }
}

let dep = new Dep
let watcher = new Watcher
// 添加订阅者
dep.addSub(watcher)
// 发布执行
dep.notify()

// 执行结果 update --->

观察者模式和订阅发布模式的区别

  • 观察者模式是由具体的目标调用,例如:当事件触发 Dep 就会去调用观察者的方法,所以订阅者和观察者之间是存在依赖的。
  • 发布订阅模式是由统一的调度中心调用,因为发布者和订阅者不需要知道对方的存在。

你可能感兴趣的:(【12-21】Vue中的观察者模式和订阅——发布模式)