博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
js设计模式--发布订阅模式
阅读量:6821 次
发布时间:2019-06-26

本文共 5128 字,大约阅读时间需要 17 分钟。

前言

本系列文章主要根据《JavaScript设计模式与开发实践》整理而来,其中会加入了一些自己的思考。希望对大家有所帮助。

文章系列

概念

发布—订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状 态发生改变时,所有依赖于它的对象都将得到通知。

场景

DOM事件

document.body.addEventListener('click', function () {    alert(2);  }, false);  document.body.addEventListener('click', function () {    alert(3);  }, false);  document.body.addEventListener('click', function () {    alert(4);  }, false);  document.body.click(); // 模拟用户点击

优缺点

优点:发布—订阅模式的优点非常明显,一为时间上的解耦,二为对象之间的解耦。

缺点:创建订阅者本身要消耗一定的时间和内存,而 且当你订阅一个消息后,也许此消息最后都未发生,但这个订阅者会始终存在于内存中。

例子

销售处订阅房源

简单的发布订阅

var Event = function() {  this.list = []}Event.prototype.add = function(listener) {  this.list.push(listener)}Event.prototype.triggle = function() {  this.list.forEach(listener => {    listener()  })}var event = new Event()event.add(()=>{console.log('房源1--80平--200万')})event.add(()=>{console.log('房源2--200平--1000万')})event.triggle()

或者

var event = {  list: [],  add(listener) {    this.list.push(listener)  },  triggle() {    this.list.forEach(listener => {      listener()    })  }}event.add(()=>{console.log('房源1--80平--200万')})event.add(()=>{console.log('房源2--200平--1000万')})event.triggle()

但这种不能区分是发不了什么消息,比如有两群人:订阅80平房源报价和订阅200瓶房源报价的人,这里两群人都会得到通知

改进

var event = {  list: {},  add(type, listener) {    if (!this.list[type]) {      this.list[type] = []    }    this.list[type].push(listener)  },  triggle(type) {    this.list[type] && this.list[type].forEach(listener => {      listener()    })  }}event.add('80平', ()=>{console.log('房源1--80平--200万')})event.add('80平', ()=>{console.log('房源2--80平--300万')})event.add('200平', ()=>{console.log('房源2--200平--1000万')})event.triggle('80平')

这里还少了一个取消订阅的功能

增加取消订阅

var event = {  list: {},  add(type, listener) {    if (!this.list[type]) {      this.list[type] = []    }    this.list[type].push(listener)  },  triggle(type) {    this.list[type] && this.list[type].forEach(listener => {      listener()    })  },  remove(type, fn) {    if (!this.list[type]) return    var index = this.list[type].findIndex(listener => listener === fn)    this.list[type].splice(index, 1)  }}var f1 = ()=>{console.log('房源1--80平--200万')}var f2 = ()=>{console.log('房源2--80平--300万')}var f3 = ()=>{console.log('房源2--200平--1000万')}event.add('80平', f1)event.add('80平', f2)event.add('200平', f3)event.remove('80平', f2)event.triggle('80平') // 房源1--80平--200万

上面代码结构还不是很清晰,我们再模拟销售部真实的场景

更真实的销售部场景

  1. 销售部
  • 销售部有很多房源,如80平的,100平的等
  • 客户可以到销售部登记自己想买的房源面积,并留下姓名。到时候如果有房源,销售部就会通知客户
  • 客户由于一些原因决定不买房的时候,可以取消订阅
  1. 客户
  • 当有房源时,客户有一个接听报价的方法
var Event = function () {  this.list = {}}Event.prototype.add = function (area, client) {  if (!this.list[area]) this.list[area] = []  this.list[area].push(client)}Event.prototype.remove = function (area, client) {  if (!this.list[area]) return  var index = this.list[area].findIndex(item => item === client)  this.list[area].splice(index, 1)}Event.prototype.triggle = function (area, price) {  if (!this.list[area]) return  this.list[area].forEach(client => {    client.listen(area, price)  })}var Client = function (name) {  this.name = name}Client.prototype.listen = function (area, price) {  console.log(`${this.name}收到${area}平的房源报价${price}`)}var client1 = new Client('client1')var client2 = new Client('client2')var event = new Event()event.add('80平', client1)event.add('100平', client1)event.add('80平', client2)event.add('300平', client1)event.remove('300平', client1)event.triggle('80平', 200) // client1收到80平平的房源报价200 client2收到80平平的房源报价200event.triggle('100平', 500) // client1收到100平平的房源报价500event.triggle('200平', 1000) //event.triggle('300平', 1000) //

上面的代码虽然已经很好了,但是还是有一个缺点:订阅者接收不到订阅之前发布的消息,如下客户3也想订阅80平的房源,但他收不到任何消息

var client3 = new Client('client3')event.add('80平', client3)

我们希望客户3也能收到消息

必须先订阅再发布吗

我们增加一个cache字段来记录历史房源报价

var Event = function () {  this.list = {}  this.cache = {}}Event.prototype.add = function (area, client) {  if (!this.list[area]) this.list[area] = []  this.list[area].push(client)  this.cache[area].forEach(price => {    client.listen(area, price)  })}Event.prototype.remove = function (area, client) {  if (!this.list[area]) return  var index = this.list[area].findIndex(item => item === client)  this.list[area].splice(index, 1)}Event.prototype.triggle = function (area, price) {  if (!this.cache[area]) this.cache[area] = []  this.cache[area].push(price)  if (!this.list[area]) return  this.list[area].forEach(client => {    client.listen(area, price)  })}var Client = function (name) {  this.name = name}Client.prototype.listen = function (area, price) {  console.log(`${this.name}收到${area}平的房源报价${price}`)}var client1 = new Client('client1')var client2 = new Client('client2')var event = new Event()// event.add('80平', client1)// event.add('100平', client1)// event.add('80平', client2)// event.add('300平', client1)// event.remove('300平', client1)event.triggle('80平', 200) // client1收到80平平的房源报价200 client2收到80平平的房源报价200event.triggle('100平', 500) // client1收到100平平的房源报价500event.triggle('200平', 1000) //event.triggle('300平', 1000) //var client3 = new Client('client3')event.add('80平', client3)event.add('100平', client3)

网站登录

假如我们正在开发一个商城网站,网站里有 header 头部、nav 导航、消息列表、购物车等模块。这几个模块的渲染有一个共同的前提条件,就是必须先用 ajax 异步请求获取用户的登录信息。

这里留给读者自己实现

转载地址:http://izlzl.baihongyu.com/

你可能感兴趣的文章
Tapestry 教程(五)实现Hi-Lo猜谜游戏
查看>>
2015年12月国内网民地域分布12强:湖北跻身上榜
查看>>
mysql-5.6安装
查看>>
LNMP环境搭建 Ubuntu篇
查看>>
设置低版本VDA注册高版本DDC
查看>>
multi-process script for ping host
查看>>
云数据库SQL Server 2008 R2版推出OSS版本数据上云
查看>>
Android 侵权案下周复审
查看>>
shell基础知识;
查看>>
RocketMQ源码分析之RocketMQ事务消息实现原理中篇----事务消息状态回查
查看>>
shell 中如何输出 n 个连续字符
查看>>
Bootstrap V4 自学开始!
查看>>
技术博客2014年4月份头条记录
查看>>
聚合国内外主流广告平台|开发者服务-KeyMob移动广告聚合平台
查看>>
解决PotPalyer不能拖放播放
查看>>
Linux安装mysql5.7
查看>>
HIVE常用操作以及函数
查看>>
【优达学城测评】SQL 支持许的数据类型(3)
查看>>
PHP CURL CURLOPT参数说明(curl_setopt)
查看>>
Learning NodeJs(1)
查看>>