发布订阅模式(Js)

一、什么是发布订阅模式?

发布订阅模式中,可以有多个订阅者,但却只能有一个发布者。当发布者发布某一新消息时,所有的订阅者都可以接收到该消息。
具体实现过程可大致分为:

  • 订阅者先在事件调度中心里注册事件(想订阅的内容)和回调函数
  • 发布者将具体事件发送到事件调度中心来触发相关事件
  • 事件调度中心处理相应的回调函数并将结果发送给对应的订阅者

为了方便理解,我们举个栗子:

	aDiv.addEventListener('click',function(){
    	console.log('一个朴实无华的div');
  	})

DOM中给元素绑定点击事件就是一种发布订阅模式。你不用关心这个div什么时候被点击,因为它被点击的时候会自动触发回调函数。

二、实现它o_O

相信大家都或多或少看过直播,我们这里就以某牙举例。
在某牙里,一旦你订阅了某个主播,那么当主播开播的时候,平台就会给你和其他订阅者推送开播消息。

	//定义发布者
	let huya = {
	  //缓存列表(事件调度中心),
	  //存放被订阅的主播和回调函数
	  anchorLists: {},
	  
	  //订阅主播
	  //fn --- 系统给用户发送的消息通知
	  listen: function (anchorName, fn) {
	  	//如果缓存列表里没有对应的主播(当第一个人订阅该主播时),
	  	//我们就在缓存列表中为其创建一个专属数组放置订阅者们
	    if (!this.anchorLists[anchorName]) {
	      this.anchorLists[anchorName] = []
	    }
	    this.anchorLists[anchorName].push(fn)
	  },
	
	  //发布消息
	  trigger: function () {
	  	//这里由于不确定推送消息时是否需要携带其它参数,所以利用
	  	//shift方法返回要发送开播提醒的主播名
	    let anchorName = Array.prototype.shift.call(arguments)
		//如果缓存列表中没有该主播的专属数组,说明没有人订阅他
	    if (!this.anchorLists.hasOwnProperty(anchorName)) {
	      console.log(`该主播尚未被订阅…o_O…`);
	      return;
	    }
	    //如果有人订阅他,取出该主播的专属数组并执行其中所有的回调函数来通知各个订阅者
	    let fnQueues = [...this.anchorLists[anchorName]]
	    fnQueues.forEach(item => (item.apply(this, arguments)))
	  }
	 }

这样,发布、订阅就完成了,但是我们应该还有一些额外的功能,比如:取消订阅、仅订阅一次。

取消订阅

	remove: function (anchorName, fn) {
	    if (!this.anchorLists[anchorName] || this.anchorLists[anchorName].length===0) {
	      console.log(`你尚未订阅该主播`);
	      return;
	    }
	    //获取缓存列表中该主播的专属数组
	    let fnLists = [...this.anchorLists[anchorName]]
	    
  //订阅者们触发remove()时系统应该强制将其注册的消息通知函数(即fn)传入,不然如果一个用户
  //取消订阅,那么所有订阅了主播的用户的消息通知函数都将被清除。这个操作应该只有系统才有权限执行。
	    
	    //虽然这里与我们的场景有些许冲突,但是其他场景里这么判断还是有必要的,所以问题不大。
	    if (!fn) {
	      fnLists && (fnLists.length = 0)
	    }
	    for (let i = 0; i < fnLists.length; i++) {
	      var obj = fnLists[i];
	      if (obj === fn) {
	      	//利用循环找到该用户注册的消息通知函数并将其删除
	        fnLists.splice(i, 1)
	      }
	    }
	    //刷新该主播的专属数组
	    this.anchorLists[anchorName] = fnLists;
	  }

这样的话,我们取消订阅的功能也完成了。

仅订阅一次

  once(anchorKey, fn) {
    function cdb() {
      fn.apply(this, arguments)
      this.remove(anchorKey, cdb)
    }
    this.listen(anchorKey, cdb)
  }

这里因为我们先前已经写好了订阅和取消订阅的方法,所以我们直接在once中用就行了,不过要注意的是,因为订阅一次功能要求消息推送函数(fn)要先执行一次再取消订阅,所以我们将消息推送函数的执行和取消订阅事件封装进一个函数(cdb)中来达到此目的。

三、测试结果

这里在node环境下运行

	//订阅者小明
	function xiaoming() {
	  let args = Array.prototype.slice.call(arguments)
	  console.log(`xiaoming,${args}开始直播了`);
	}
	//订阅者张三
	function zhangsan() {
	  let args = Array.prototype.slice.call(arguments)
	  console.log(`zhangsan,${args}开始直播了`);
	}

对once功能进行测试

	//订阅者们订阅相关事件
	huya.listen('uzi',xiaoming)
	huya.once('uzi',zhangsan)
	//系统发布消息
	huya.trigger('uzi','乌兹')
	huya.trigger('uzi','乌兹')

测试图
对remove功能进行测试

	huya.listen('uzi',xiaoming)
	huya.listen('uzi',zhangsan)
	
	huya.trigger('uzi','乌兹')
	//小明取消订阅uzi
	huya.remove('uzi',xiaoming)
	huya.trigger('uzi','乌兹')

在这里插入图片描述
当连续多次取消订阅同个主播时,也会打印信息:‘你尚未订阅该主播’(亲测有效)。
到这儿,我们的发布订阅模式就完成了,不足之处还请大家多多指教(手动抱拳)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
发布订阅模式又称观察者模式,是一种常见的设计模式,它定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。下面是手写JavaScript发布订阅模式的一种实现方式: ```javascript function PubSub() { this.subscribers = {}; } PubSub.prototype.subscribe = function(event, callback) { if (!this.subscribers[event]) { this.subscribers[event] = []; } this.subscribers[event].push(callback); }; PubSub.prototype.unsubscribe = function(event, callback) { if (!this.subscribers[event]) { return; } var index = this.subscribers[event].indexOf(callback); if (index > -1) { this.subscribers[event].splice(index, 1); } }; PubSub.prototype.publish = function(event, data) { if (!this.subscribers[event]) { return; } this.subscribers[event].forEach(function(callback) { callback(data); }); }; ``` 使用方式如下: ```javascript var pubsub = new PubSub(); function callback1(data) { console.log('callback1:', data); } pubsub.subscribe('event1', callback1); function callback2(data) { console.log('callback2:', data); } pubsub.subscribe('event2', callback2); pubsub.publish('event1', { message: 'hello' }); pubsub.publish('event2', { message: 'world' }); pubsub.unsubscribe('event1', callback1); pubsub.publish('event1', { message: 'hello again' }); ``` 输出结果为: ``` callback1: {message: "hello"} callback2: {message: "world"} ``` 当调用 `publish` 方法时,订阅了该事件的所有回调函数都将被执行,并且可以传递一个数据对象作为参数。调用 `subscribe` 方法注册一个回调函数,当该事件发布时,该回调函数将被执行。调用 `unsubscribe` 方法取消订阅

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值