精华内容
下载资源
问答
  • 现在网上很多文章都讲不清楚什么是发布/订阅和观察者模式,要不就是复制粘贴过来的,百度都能查处一大推一模一样的...那么这个房子的主人也就是房东是一个发布者(publish),你或者其他需要买房的人就是订阅者(subs

    现在网上很多文章都讲不清楚什么是发布/订阅和观察者模式,要不就是复制粘贴过来的,百度都能查处一大推一模一样的文章。很气愤!!!

    那么我将根据自己的理解去解释发布/订阅和观察者模式,如果有大佬觉得不对,欢迎在评论区留下宝贵意见

    发布/订阅模式

    发布/订阅模包含:

    • 发布者
    • 订阅者
    • 信号中心

    假设你要买房子,但是你有没有房源信息,那么你会找到谁?你肯定会去问房屋中介,那么这个房屋中介就是一个信号中心。那么这个房子的主人也就是房东是一个发布者(publish),你或者其他需要买房的人就是订阅者(subscribe)。

    那么在Vue是如何实现的呢?

    // Vue 中使用方法
    let vm = new Vue()
    
    // 订阅者
    vm.$on('change', () => {
        console.log('change')
    })
    
    // 订阅者
    vm.$on('change', () => {
        console.log('change1')
    })
    
    // 发布者
    vm.$emit('change')

    以上就是 Vue 中使用的方法,通过$on方法来订阅change事件,通过$emit方法来发布change事件,那么订阅者获取到事件之后就会执行相对应的方法。这就是发布/订阅模式(publish-subscribe pattern )。接下来我们老模拟实现一个发布/订阅模式来加深印象

    首选我们来分析下订阅/发布模式是如何实现的

    1. 定义一个类Vue(也可以是其他名称)
    2. 类里面有两个方法$on(订阅者)和$emit(发布者)
    3. $on方法里接受两个参数,一个是事件类型,另一个是执行的方法
    4. $emit方法里接受一个参数,事件类型

    接下来根据我们分析的情况通过代码来模拟实现如下:

    // 事件中心
    class Vue {
        constructor () {
            // 创建一个空对象,结构是{ event: [function1, function2, ...] }
            this.subs = Object.create(null)
        }
        
        // 定义$on方法(订阅者)event: 事件名称 handler: 需要执行的方法
        $on (event, handler) {
            // 匹配对应的事件,如果事件存在就取事件对应的值,否则就取空数组
            this.subs[event] = this.subs[event] || []
            
            // 找到对应的事件将值(函数)push到对应的事件值中
            this.subs[event].push(handler)
        }
        
        // 定义$emit方法(发布者)
        $emit(event) {
            // 判断当前事件是否存在,存在执行对应值的方法
            if(this.subs[event]) {
                this.subs[event].forEach(handler => {
                    handler()
                })
            }
        }
    }
    
    // 测试
    let vm = new Vue()
    vm.$on('change', () => {
        console.log('change')
    })
    vm.$emit('change')

    浏览器执行以上代码会发现控制台打印出'change',以上就是发布/订阅模式的实现方式

    关注我后续我会继续更新观察者模式

     

    展开全文
  • vue发布订阅者模式

    千次阅读 2020-01-13 10:54:07
    https://www.jianshu.com/p/2ec316ca0f8b
    展开全文
  • Vue 发布订阅模式

    2021-09-23 08:43:26
    发布订阅模式订阅者发布者,信号中心 我们假定,存在一个“信号中心”,某个任务执行完成,就向信号中心"发布"(publish)一个信号,其它任务可以向信号中心“订阅”(subscribe)这个信号,从而知道什么时候自己...

    发布订阅模式:订阅者,发布者,信号中心

    我们假定,存在一个“信号中心”,某个任务执行完成,就向信号中心"发布"(publish)一个信号,其它任务可以向信号中心“订阅”(subscribe)这个信号,从而知道什么时候自己可以开始执行。这就叫做"发布/订阅模式"(publish-subscribe pattern)

    家长向学生所在的班级订阅了获取学生考试成绩的事件,当老师公布学生的成绩后,就会自动通知学生的家长。

    在整个案例中,学生所在的班级为信号中心,老师为发布者,家长为订阅者

    Vue 的自定义事件就是基于发布订阅模式来实现的。

    下面通过Vue中兄弟组件通信过程,来理解发布订阅模式

    // eventBus.js
    // 事件中心
    let eventHub=new Vue()
    //ComponentA.vue
    addTodo:function(){
        //发布消息(事件)
        eventHub.$emit('add-todo',{text:this.newTodoText})
        this.newTodoText=''
    }
    //ComponentB.vue
    //订阅者
    created:function(){
        //订阅消息(事件)
        eventHub.$on('add-todo',this.addTodo)
    }

    通过以上代码,我们可以理解发布订阅模式中的核心概念。

    下面我们模拟Vue中的自定义事件的实现

    下面我们先来做一个基本的分析:

    先来看如下代码:

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Vue 自定义事件</title>
      </head>
      <body>
        <script src="./js/vue.js"></script>
        <script>
          //Vue自定义事件
          let vm = new Vue();
          //注册事件(订阅消息)
          vm.$on("dataChange", () => {
            console.log("dataChange");
          });
          vm.$on("dataChange", () => {
            console.log("dataChange");
          });
          //触发事件(发布消息)
          vm.$emit("dataChange");
        </script>
      </body>
    </html>

    通过上面的代码,我们可以看到$on实现事件的注册,而且可以注册多个事件,那么我们可以推测在其内部有一个对象来存储注册的事件,对象的格式为:

    {'click':[fn1,fn2],'change':[fn]}

    以上格式说明了,我们注册了两个事件,分别为clickchange.

    下面我们根据以上的分析过程,来模拟实现自定义事件。

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>发布订阅模式</title>
      </head>
      <body>
        <script>
          class EventEmitter {
            constructor() {
              // {'click':[fn1,fn2],'change':[fn]}
              // 存储事件与处理函数的对应关系
              this.subs = {};
            }
            //注册事件
            //第一个参数为事件名称
            // 第二个参数为处理函数
            // 将对应的处理函数添加到subs对象中
            $on(eventType, fn) {
              //判断对应的eventType是否有相应的处理函数,如果有,直接添加到数组中,如果没有返回一个空数组。
              if (!this.subs[eventType]) {
                this.subs[eventType] = [];
              }
              this.subs[eventType].push(fn);
            }
            //触发事件
            $emit(eventType) {
              if (this.subs[eventType]) {
                this.subs[eventType].forEach((handler) => {
                  handler();
                });
              }
            }
          }
          //测试代码
          let em = new EventEmitter();
          em.$on("click", () => {
            console.log("click1");
          });
          em.$on("click", () => {
            console.log("click2");
          });
          em.$emit("click");
        </script>
      </body>
    </html>
    展开全文
  • 主要介绍了Vue发布订阅模式实现过程图解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • 观察者模式 目标者对象和观察者对象有相互依赖的关系,观察者对某个对象的状态进行观察,如果对象的状态发生改变,...Vue中响应式数据变化是观察者模式 每个响应式属性都有dep,dep存放了依赖这个属性的watcher,w...

    观察者模式

    目标者对象和观察者对象有相互依赖的关系,观察者对某个对象的状态进行观察,如果对象的状态发生改变,就会通知所有依赖这个对象的观察者,

    1,目标者对象 Subject,拥有方法:添加 / 删除 / 通知 Observer

    2,观察者对象 Observer,拥有方法:接收 Subject 状态变更通知并处理;

    3,目标对象 Subject 状态变更时,通知所有 Observer

    Vue中响应式数据变化是观察者模式 每个响应式属性都有depdep存放了依赖这个属性的watcherwatcher是观测数据变化的函数,如果数据发生变化,dep就会通知所有的观察者watcher去调用更新方法。因此, 观察者需要被目标对象收集,目的是通知依赖它的所有观察者。那为什么watcher也要存放dep呢?是因为当前正在执行的watcher需要知道此时是哪个dep通知了自己。

    beforeCreate之后,created之前调用observe(data)初始化响应式数据,以下是简化版代码(没有处理数组的劫持)

    class Observer {
        // 需要对value的属性描述重新定义
        constructor(value) {
          this.walk(value); // 初始化的时候就对数据进行监控
        }
        walk(data) {
          Object.keys(data).forEach((key) => {
            defineReactive(data, key, data[key]);
          });
        }
      }
      
      function defineReactive(data, key, value) {
        // value 可能是一个对象,要递归劫持,所以数据不能嵌套太深
        observe(value);
        let dep = new Dep();
        Object.defineProperty(data, key, {
          get() {
            // 如果有 watcher,就让 watcher 记住 dep,防止产生重复的 dep, 同时 dep 也收集此 watcher
            if (Dep.target) {
              dep.depend();
            }
            return value;
          },
          set(newVal) {
            // 数据没变动则不处理
            if (value === newVal) return;
            observe(newVal); // 如果新值是个对象,递归拦截
            value = newVal; // 设置新的值
            dep.notify(); // 通知收集的 watcher 去更新
          },
        });
    }
    function observe(data) {
        // 不是对象则不处理,isObject是用来判断是否为对象的函数
        if (Object.prototype.toString.call(data)!== '[object Object]') return;
        // 通过类来实现数据的观测,方便扩展,生成实例
        return new Observer(data);
    }
    observe(data)

    created之后,mouted之前调用mountComponent挂载组件,以下是简化版代码(没有处理watchcomputedwatcher

    class Dep {
        static target = null
        constructor() {
          this.id = id++;
          this.subs = []; // 存放依赖的watcher
        }
        depend() {
          // 让正在执行的watcher记录dep,同时dep也会记录watcher
          Dep.target.addDep(this);
        }
        addSub(watcher) {
          // 添加观察者对象
          this.subs.push(watcher);
        }
        notify() {
          // 触发观察者对象的更新方法
          this.subs.forEach((watcher) => watcher.update());
        }
    }
    class Watcher {
        constructor(vm, exprOrFn) {
          this.vm = vm;
          this.deps = [];
          // 用来去重,防止多次取同一数据时存入多个相同dep
          this.depId = new Set();
          // exprOrFn是updateComponent
          this.getter = exprOrFn;
          // 更新页面
          this.get();
        }
        get() {
          Dep.target = watcher; // 取值之前,收集 watcher
          this.getter.call(this.vm); // 调用updateComponent更新页面
          Dep.target = null; // 取值完成后,将 watcher 删除
        }
        // dep.depend执行时调用
        addDep(dep) {
            let id = dep.id;
            let has = this.depId.has(id);
            if (!has) {
                this.depId.add(id);
                // watcher存放dep
                this.deps.push(dep);
                // dep存放watcher
                dep.addSub(this);
            }
        }  
        // 更新页面方法,dep.notify执行时调用
        update() {
            this.get(); // 一修改数据就渲染更新
        }
    }
    function mountComponent(vm) {
        // 渲染更新页面
        let updateComponent = () => {
          let vnode = vm._render(); // 生成虚拟节点 vnode
          vm._update(vnode); // 将vnode转为真实节点
        };
        // 每个组件都要调用一个渲染 watcher
        new Watcher(vm, updateComponent);
    }
    mountComponent(vm)

    发布订阅模式

    基于一个事件中心,接收通知的对象是订阅者,需要 先订阅某个事件,触发事件的对象是发布者,发布者通过触发事件,通知各个订阅者。 js中事件绑定,就是发布订阅模式

    发布订阅模式相比观察者模式多了个事件中心,订阅者和发布者不是直接关联的。

    vue中的事件总线就是使用的发布订阅模式

    // 事件总线
    class Bus {
      constructor() {
        // 用来记录事件和监听该事件的数组
        this.listeners = {};
      }
      // 添加指定事件的监听者
      $on(eventName, handler) {
        this.listeners[eventName].add(handler);
      }
      // 取消监听事件
      $off(eventName, handler) {
        this.listeners[eventName].delete(handler);
      }
      // 触发事件
      $emit(eventName, ...args) {
        this.listeners[eventName].forEach((fn) => fn(...args));
      }
    }

    事件总线的具体使用可以查看这篇   Vue之事件总线

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

    目标和观察者之间是互相依赖的。

    发布订阅模式是由统一的调度中心调用,发布者和订阅者不知道对方的存在。

    推荐阅读:

    史上最详细axios,读完你就全部懂了

    vue后台项目中遇到的技术难点以及解决方案

    前端面试题拿到百度京东offer的,前端面试题2021及答案

    展开全文
  • 观察者模式 ...发布者内部需要一个属性去记录所有的订阅者,也就是所该属性是一个数组 还需要一个方法去添加所有的订阅者到数组中存储起来 还需要一个方法当事件发生时去通知所有订阅者执行update
  • 数据劫持+发布者订阅者模式 数据劫持 new vue时候拿到data中返回的对象,通过object.key().forEach()遍历,给原来对象中的属性通过object.defineProperty重新定义赋值。通过这个方法在对象使用这个属性的时候(obj...
  • 发布订阅模式和观察者模式 发布/订阅模式 发布/订阅模式 订阅者 发布者 信号中心 我们假定,存在一个“信号中心”,某个任务执行完成,就向信号中心“发布”(publish)一个信号,其他任务可以向信号中心“订阅...
  • vue发布订阅者模式$emit、$on

    千次阅读 2019-07-21 11:19:10
    vue中自定义事件,就是用了发布订阅者模式,vm.$on通过自定义事件,事先订阅一件事,vm.$emit通过自定义事件发布消息,vm.$on会接收到。非父子组件数据传递,通常会用到这两个方法: 下边我们先来用js实现发布...
  • 发布 订阅模式 // 事件触发器 class EventEmitter { constructor () { // { 'click': [fn1, fn2], 'change': [fn] } this.subs = Object.create(null) } // 注册事件 $on (eventType, handler) { ...
  • 要搞清楚vue中的双向数据绑定原理,就必须理解什么是发布、订阅者模式!! 1、首先想好谁是发布者、谁是订阅者(例如NBA专栏就是发布者,NBA球迷就是订阅者) 2、然后给发布者添加一个缓存列表,用于存放回调函数...
  • 发布者订阅者模式

    2021-01-14 09:49:33
    1 发布订阅模式理解 假定存在一个信号中心,某个任务执行完成就向信号中心发布一个任务,其他任务可以向信号中心订阅这个任务...注:vue中兄弟组件通信过程就是通过发布者订阅者模式实现的。 2 发布订阅者模式代码 ...
  • 发布/订阅模式和观察者模式通常被混为一谈,但它们在Vue中有着不同的应用场景。 发布/订阅模式核心: 订阅者 发布者 信号中心(事件中心) 我们假定:存在一个“信号中心”,某个任务执行完成,就向信号中心“发布...
  • Vue双向绑定(数据劫持,发布订阅者模式,diff算法) 最近一段时间自己找点东西学习,因为面试vue双向绑定问的挺多的,就想去深入研究一下本质原理,说是本质也不算,就是看了看别人的研究总结一点自己的看法和理解...
  • class Event { constructor (){ this .events = {} ...// vue中数据劫持结合发布/...对发布订阅者的通俗理解 订阅可以理解为寄存,发布理解为寄存的拿出调用,可以寄存很多个,拿出很多个 观察者模式主要是监听
  • zh众所周知,vue2.x版本是通过Object.defineProperty() 种的get进行拦截,set进行发送,其实这只是表面理解,实际运用的是JavaScript的 订阅者发布者模式。首先,了解一下什么是订阅者发布者模式 吧。w3c 上是...
  • 2.在触发时,逐个触发(发布)**。 3.还可以根据key来删除某个监听函数。 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="wid...
  • 而发布订阅模式里,却不仅仅只有发布者订阅者两个角色,还有一个经常被我们忽略的 —— 经纪人Broker 往更深层次讲: 观察者和被观察者,是松耦合的关系 发布者订阅者,则完全不存在耦合 从使用层面上讲: 观察...
  • 发布订阅模式:也称作观察者模式,定义对象间的一对多的依赖关系,当一个对象的状态发 生改变 时,所有依赖于它的对象都将得到通知; 编码中常用的场景: //订阅事件 window.addEventListener('click',()=&...
  • 订阅发布模式定义了一种一对多的依赖关系,让多个订阅者对象同时监听某一个主题对象。这篇文章主要介绍了发布订阅模式vue中的实际运用,需要的朋友可以参考下
  • 。。 转载于:https://www.cnblogs.com/stephenleee/p/10298939.html
  • 发布订阅模式中订阅者发布者没有关联,所以观察者模式中包含了发布订阅模式(watcher和deep) 2、数据传递 /** *1.vue是单向数据流 *2.Vue组件间传值的方式及之间的区别 *3.props和emit父组件向子...
  • 发布订阅模式 $ 定义 基于一个自定义事件通道,收集与之相关的订阅成员,通过发布自定义事件的方式通知各个订阅成员。 $ Vue中的语法 // Vue 自定义事件 let vm = new Vue() // 注册事件(订阅消息) vm.$on('data...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 7,426
精华内容 2,970
关键字:

vue发布者订阅者模式

vue 订阅