一. 认识发布订阅者模式

发布订阅者模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象都将得到通知。我们一般用事件模型来代替传统发布订阅模式。

就拿用户订阅公众号来说,用户根据需求来订阅自己喜欢的公众号,一旦公众号有新的文章,便会主动推给每个订阅它的用户,这种模式解决了很多日常的需求,就比如现在比较流行的框架 vue , 其关键的动态绑定原理就是由订阅发布者模式和数据劫持技术来实现,接下来我们来更深入了解。

二. 发布订阅模式的实现

实现思想:在一个全局变量对象中封装一个监听事件和一个发布事件,首先需要有一个用来保存事件和监听的对象,将订阅相同的事件保存在同一个数组中,发布某个订阅后,遍历数组中的函数,依次执行。

        let Emitter = {};Emitter.list = {};  // 用来缓存事件// 监听事件Emitter.on = function ( key, fn ) {(this.list[ key ] || (this.list[ key ] = [])).push( fn );};// 发布事件Emitter.emit = function (key, ...args) {let list = this.list[key];if(list.length == 0){return}list.forEach(( fn )=>{fn.apply(this, args);})};// 取消订阅Emitter.remove = function (key, fn) {let fns = this.list[key];if(fns.length == 0) {return}if( !fn ) {return this.list[key].length = 0;}for(let i = 0,l = fns.length; i < l ; i++){if(fn == fns[i]) {this.list[key].splice(i, 1);}}};let Listen1 = function( data ) {console.log("我是订阅者1");console.log("以下是文章内容:" +data );}let Listen2 = function(data) {console.log("我是订阅者2")}Emitter.on('公众号1', Listen1);Emitter.on('公众号1', Listen2);Emitter.emit('公众号1','这是文章内容!');Emitter.remove('公众号1', Listen1);

三. 实际开发应用

  • 获取登录信息数据

首先我们模拟了 3 秒后获取到服务器传回的数据,虽然我们可以将所有渲染写入异步回调中,但是每次增加新的需求时,你必须找到原来的代码行修改,而使用订阅发布模式,我们只需将业务集中到新的需求上,让其监听 login 便可,很方便新增、管理或删除需求。

        // 假定从服务器请求拿到用户登录信息数据,账号昵称,头像等等(()=>{setTimeout(()=>{let data = {nicname: "石头山",photo: "菊花"};Emitter.emit('login', data);},2000)})();let renderNicname = function( { nicname } ) { // 渲染console.log("我的昵称是: ", nicname)}let renderPhoto = function( { photo } ) { // 渲染console.log("我的头像: ", photo);}Emitter.on('login', renderNicname);Emitter.on('login', renderPhoto);
  • 模块间的通信

        假如有一个需求,在模块 a 中点击按钮,在模块 中显示记录 a 中的点击次数。

        // 模块 alet count = 0;let addA = function(count){}button.onclick = function() {Emitter.emit('add', count++); }// 模块BEmitter.on('add',( count )=> {document.body.innerHTML = count;})

四. 订阅发布模式的扩展

我们来想一个问题,我们平时所接触的订阅发布都是先订阅,然后再发布。那我们反着尝试一下,先发布,再订阅,毫无疑问是没有任何效果,但这在实际开发中又是一个必要的需求。比如QQ离线,你不在线时先把其他人给你发的消息保存下来,当你上线后,便可以接收到这些消息。

因此我们可以来实现一个离线缓冲空间,将未被订阅的发布函数存放在其中,当有新的订阅时,从新发布。

分析:我们重新修改代码,Emitter 中新增加了 cache 离线空间,用来存储先发布的事件,再 emit 执行时,我们新增了一个条件,判断是否存在该订阅,如果不存在将其保存到 cache 中,在 on 执行时,增加了一条分支,用来判断该订阅是否为先发布的订阅,如果是,则从新发布该订阅,并从 cache 中删除该条发布记录。

               //   订阅事件let Emitter = {};Emitter.list = {};  // 用来缓存事件Emitter.cache = {};// 监听事件Emitter.on = function ( key, fn ) {(this.list[ key ] || (this.list[ key ] = [])).push( fn );if(this.cache[ key ]) {Emitter.emit(key, ...this.cache[ key ]); // 重新发布并且删除缓存delete this.cache[key];}};// 发布事件Emitter.emit = function (key, ...args) {let list = this.list[key];if( !list ){ // 如果不存在该订阅,则先缓存console.log("不存在该订阅先缓存");this.cache[key] = args;return;}if( list.length == 0 ){return ;}list.forEach(( fn )=>{fn.apply(this, args);})};

五. 总结

优点:一是时间上的解耦,二是对象之间的解耦。

缺点:创建订阅者本身消耗时间和内存,并且防止过度嵌套订阅,引起不必要的麻烦。

发布订阅模式是很重要也是常用的设计模式,可以广泛应用于异步编程中,这是一种替代传递回调函数的方案。发布订阅让两个对象松耦合在一起,虽然不清楚彼此细节,但这不影响他们之间的通信。但是有时候使用回调而不是发布订阅模式显得更加的优雅,所以使用时我们要依情况而定。

js设计模式之发布订阅者模式相关推荐

  1. 从东京奥运会看js设计模式之发布订阅模式

    开篇废话:本篇文章介绍发布-订阅模式,想必很多人听说过有一种观察者模式,网上既有资料说这是两种不同的设计模式,也有说这是一种模式,我倾向于认同他们是同一种设计模式.不必过于纠结 开篇楔子:东京奥运会已 ...

  2. js观察者模式和发布订阅者模式

    一.观察者模式的理解 观察者模式:一个对象(称为subject)维持一系列依赖于它的对象(称为observer),将有关状态的任何变更自动通知给它们(观察者). 二.发布/订阅模式的理解 发布/订阅模 ...

  3. JavaScript设计模式之发布-订阅模式(观察者模式)-Part1

    <JavaScript设计模式与开发实践>读书笔记. 发布-订阅模式又叫观察者模式,它定义了对象之间的一种一对多的依赖关系.当一个对象的状态发生改变时,所有依赖它的对象都将得到通知. 例如 ...

  4. 设计模式-观察者模式 发布/订阅模式

    设计模式-观察者模式 发布/订阅模式 代码 观察者接口 public interface IHanFeiZi{// 当吃早饭时public void havBreakFast();// 进行娱乐活动时 ...

  5. 设计模式之发布订阅模式

    发布--订阅模式简介 发布--订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,多个观察者对象都依赖于一个目标对象,当目标对象的状态发生变化时,所有依赖于这个对象的观察者对象都会收到通知. ...

  6. JavaScript设计模式 -发布订阅者模式

    1. 定义 发布订阅者模式又叫观察者模式,他定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得将得到通知 案例: 小明最近看上了一套房子,到了售楼处之后才被告知,该楼 ...

  7. JavaScript设计模式:观察者模式与发布订阅者模式实现

    观察者模式 当对象之间存在一对多的依赖关系时,其中一个对象的状态发生改变,所有依赖它的对象都会收到通知,这就是观察者模式. 在观察者模式中,只有两种主体:目标对象 (Subject) 和 观察者 (O ...

  8. Vue设计模式,发布订阅,响应式原理(简略版)

    Vue mvvm框架是什么? mvvm框架(model-view-viewMode),本质是mvc框架的改进版,mvc框架一旦项目复杂度越来越高,代码量大,维护起来很难,尤其管理层,controlle ...

  9. JavaScript 发布订阅者模式和观察者模式及区别

    一.发布订阅模式 发布订阅模式其实是一种对象间一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到状态改变的通知. 多方订阅,一方发布,订阅放会收到通知 举例:教学楼中每个教室都有 ...

  10. EventBus—思考观察者模式与发布订阅者模式

    EventBus系列文章: EventBus-使用实践 EventBus-源码解析 1. 概述 EventBus是基于发布订阅者模式的消息处理框架. EventBus is an open-sourc ...

最新文章

  1. [裴礼文数学分析中的典型问题与方法习题参考解答]5.1.5
  2. (转)国外软件外包项目网站(适用软件兼职)
  3. mybatis动态查询列名,#与¥
  4. 简述生成式对抗网络 GAN
  5. linux上离线安装bcp,无法在Linux上安装Pyodbc
  6. Java 8星期五:Java 8的阴暗面
  7. 软件也要歧视大龄程序员吗?
  8. python sybase安装
  9. Bzoj3894文理分科
  10. 菜鸡程序员的一天都在折腾些什么?
  11. 怡红快绿 [转自TK's Blog]
  12. Project(1)——创建数据库、实体类、用户注册的持久层
  13. SystemInit()时钟系统初始化函数解析
  14. CSS line-height属性
  15. 手机百度打不开html网页,手机百度为什么打不开网页 网页打不开解决方法
  16. pyinstxtractor 源码分析及填坑
  17. 第四周.直播.03.论文带读+GAT
  18. 使用telnet远程华为路由器及CRT使用连接
  19. i5四核八线程怎么样_英特尔处理器是六核六线程好,还是四核八线程好?
  20. Android_常驻进程(杀不死的进程)

热门文章

  1. (2017.03.12更新)CnCrypt文件保险箱1.19,兼容TrueCrypt加密卷
  2. C程序实例1--个人通讯录管理系统
  3. 计算机同步不了计算机策略,修复sysvol netlog共享和组策略不同步组策略丢失等问题...
  4. 面试经验|传音控股自动化测试
  5. 推荐3款手机远程控制电脑的软件 专业 好用 免费
  6. win10绝地求生游戏崩溃怎么解决
  7. diskgenius创建efi分区_找不到引导分区 启动分区不存在 怎么创建efi系统分区
  8. c语言链表详解(超详细)
  9. MongoDB下载安装教程 全
  10. LCD和LED屏幕的工作原理总结