js 发布订阅模式应用场景 自己手写一个简易的发布订阅模块
我们先写一个简单的发布订阅:
<!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 type="text/javascript">
var shopObj = {} // 定义发布者 卖家对象
shopObj.list = [] // 缓存列表 存放订阅函数
<span class="token comment">// 添加订阅者</span>
shopObj<span class="token punctuation">.</span><span class="token function-variable function">listen</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">fn</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
shopObj<span class="token punctuation">.</span>list<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>fn<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token comment">// 发布消息</span>
shopObj<span class="token punctuation">.</span><span class="token function-variable function">trigger</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> i<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">,</span> fn<span class="token punctuation">;</span> fn <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>list<span class="token punctuation">[</span>i<span class="token operator">++</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token function">fn</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> arguments<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token comment">// 添加第一个订阅者</span>
shopObj<span class="token punctuation">.</span><span class="token function">listen</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">color<span class="token punctuation">,</span> size</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">订阅者1:颜色是</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${<!-- --></span>color<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">, 尺码是</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${<!-- --></span>size<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token comment">// 添加第二个订阅者</span>
shopObj<span class="token punctuation">.</span><span class="token function">listen</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">color<span class="token punctuation">,</span> size</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">订阅者2:颜色是</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${<!-- --></span>color<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">, again尺码是</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${<!-- --></span>size<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token comment">// 发布第一个消息 本意是要通知第1个订阅者 橘黄色 42尺码的货到了</span>
shopObj<span class="token punctuation">.</span><span class="token function">trigger</span><span class="token punctuation">(</span><span class="token string">'orange'</span><span class="token punctuation">,</span> <span class="token number">42</span><span class="token punctuation">)</span>
<span class="token comment">// 发布第二个消息 本意是要通知第2个订阅者 黑色 39尺码的货到了</span>
shopObj<span class="token punctuation">.</span><span class="token function">trigger</span><span class="token punctuation">(</span><span class="token string">'black'</span><span class="token punctuation">,</span> <span class="token number">39</span><span class="token punctuation">)</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span>
可以看到,已经可以订阅消息,并且发布消息,但是有个问题,就是发布消息的时候,把消息发送给所有订阅者了,怎么才能解决这个问题呢?
我们回忆一下,我们在使用发布订阅的时候,是不是这样使用的,要传入一个标识:
然后在触发时候,和订阅时候传入的标识对应上,是不是就能解决这个问题了
我们这样改造: 添加订阅时候,传入一个标识符key, 如果缓存列表里不存在对应的list[key]
,那么就创建一个对应的list[key]
初始值是一个空数组[]
如果有的话,直接把回调函数push进入对应的list[key]
完整代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>发布订阅模式2-优化</title>
</head>
<body>
<script type="text/javascript">
var shopObj = {} // 定义发布者 卖家对象
shopObj.list = [] // 缓存列表 存放订阅函数
<span class="token comment">// 添加订阅者</span>
shopObj<span class="token punctuation">.</span><span class="token function-variable function">listen</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">key<span class="token punctuation">,</span> fn</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token comment">// 没有对应key的话就创建一个数组</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token keyword">this</span><span class="token punctuation">.</span>list<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">this</span><span class="token punctuation">.</span>list<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token punctuation">}</span>
<span class="token comment">// 然后再把回调函数push进list[key]</span>
shopObj<span class="token punctuation">.</span>list<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>fn<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token comment">// 发布消息</span>
shopObj<span class="token punctuation">.</span><span class="token function-variable function">trigger</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token comment">// 获取对应的key</span>
<span class="token keyword">var</span> key <span class="token operator">=</span> <span class="token class-name">Array</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function">shift</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>arguments<span class="token punctuation">)</span> <span class="token comment">// 这里因为arguments是一个类数组 没有shift方法 需要借用</span>
<span class="token keyword">var</span> fns <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>list<span class="token punctuation">[</span>key<span class="token punctuation">]</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>fns <span class="token operator">||</span> fns<span class="token punctuation">.</span>length <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">return</span>
<span class="token punctuation">}</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> i<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">,</span> fn<span class="token punctuation">;</span> fn <span class="token operator">=</span> fns<span class="token punctuation">[</span>i<span class="token operator">++</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token function">fn</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> arguments<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token comment">// 添加第一个订阅者dean</span>
shopObj<span class="token punctuation">.</span><span class="token function">listen</span><span class="token punctuation">(</span><span class="token string">'dean'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">color<span class="token punctuation">,</span> size</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">订阅者dean:颜色是</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${<!-- --></span>color<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">, 尺码是</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${<!-- --></span>size<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">的鞋子到货了!</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token comment">// 添加第二个订阅者jing</span>
shopObj<span class="token punctuation">.</span><span class="token function">listen</span><span class="token punctuation">(</span><span class="token string">'jing'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">color<span class="token punctuation">,</span> size</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">订阅者jing:颜色是</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${<!-- --></span>color<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">, again尺码是</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${<!-- --></span>size<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">的鞋子到货了!</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token comment">// 发布第一个消息 通知第dean 橘黄色 42尺码的鞋子到货了</span>
shopObj<span class="token punctuation">.</span><span class="token function">trigger</span><span class="token punctuation">(</span><span class="token string">'dean'</span><span class="token punctuation">,</span> <span class="token string">'orange'</span><span class="token punctuation">,</span> <span class="token number">42</span><span class="token punctuation">)</span>
<span class="token comment">// 发布第二个消息 通知第jing 黑色 39尺码的货到了</span>
shopObj<span class="token punctuation">.</span><span class="token function">trigger</span><span class="token punctuation">(</span><span class="token string">'jing'</span><span class="token punctuation">,</span> <span class="token string">'black'</span><span class="token punctuation">,</span> <span class="token number">39</span><span class="token punctuation">)</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span>
/pre>
我们优化一下代码,再添加一个取消订阅:
var event = {
list: [],
listen: function(key, fn) {
// 没有对应key的话就创建一个数组
if (!this.list[key]) {
this.list[key] = []
}
// 然后再把回调函数push进list[key]
shopObj.list[key].push(fn)
},
trigger: function() {
// 获取对应的key
var key = Array.prototype.shift.call(arguments)
var fns = this.list[key]
if (!fns || fns.length === 0) {
return
}
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">,</span> fn<span class="token punctuation">;</span> fn <span class="token operator">=</span> fns<span class="token punctuation">[</span>i<span class="token operator">++</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token function">fn</span><span class="token punctuation">(</span><span class="token operator">...</span>arguments<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
},
// 取消订阅
remove: function(key, fn) {
var fns = this.list[key]
if (!fns) {
return false
} else {
for (var i = fns.length - 1; i >= 0; i–) {
var _fn = fns[i]
if (_fn == fn) {
fns.splice(i, 1)
}
}
}
}
}
代码还可以用立即执行函数封装一下:
// 代码封装成立即执行函数
var Event = (function() {
var list = [],
listen,
trigger,
remove;
listen = function(key, fn) {
// 没有对应key的话就创建一个数组
if (!this.list[key]) {
this.list[key] = []
}
// 然后再把回调函数push进list[key]
shopObj.list[key].push(fn)
},
trigger = function() {
// 获取对应的key
var key = Array.prototype.shift.call(arguments)
var fns = this.list[key]
if (!fns || fns.length === 0) {
return
}
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">,</span> fn<span class="token punctuation">;</span> fn <span class="token operator">=</span> fns<span class="token punctuation">[</span>i<span class="token operator">++</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token function">fn</span><span class="token punctuation">(</span><span class="token operator">...</span>arguments<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token function-variable function">remove</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">key<span class="token punctuation">,</span> fn</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">var</span> fns <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>list<span class="token punctuation">[</span>key<span class="token punctuation">]</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>fns<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">return</span> <span class="token boolean">false</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> fns<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span> i <span class="token operator">>=</span> <span class="token number">0</span><span class="token punctuation">;</span> i<span class="token operator">--</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">var</span> _fn <span class="token operator">=</span> fns<span class="token punctuation">[</span>i<span class="token punctuation">]</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>_fn <span class="token operator">==</span> fn<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
fns<span class="token punctuation">.</span><span class="token function">splice</span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
return {
listen,
trigger,
remove
}
})()
我们再看一下,发布订阅模式的使用场景: 解决异步调用中的强耦合问题:
这种强耦合代码,缺点是,修改一个地方,其他地方都要跟着一起修改
使用发布订阅模式修改:
我们接着在vue里面自己手写一个简易的发布订阅模块:
Main.vue
<template>
<div>
<el-input type="text" v-model="name" placeholder="Input name"></el-input>
<el-button type="primary" @click="handlePub">Pub</el-button>
<Son />
</div>
</template>
Son.vue
<template>
<div>
<h1>{ { content}}</h1>
</div>
</template>
pubsub2.js
var Event = (function(){
var list = [],
listen,
trigger,
remove;
listen = function (key, fn) {
// 没有对应key的话就创建一个数组
if (!list[key]) {
list[key] = []
}
// 然后再把回调函数push进list[key]
list[key].push(fn)
},
trigger = function () {
// 获取对应的key
var key = Array.prototype.shift.call(arguments)
var fns = list[key]
if (!fns || fns.length === 0) {
return
}
<span class="token comment">// for (var i=0, fn; fn = fns[i++];) {<!-- --></span>
<span class="token comment">// fn(...arguments)</span>
<span class="token comment">// }</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i<span class="token operator"><</span> fns<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">var</span> fn <span class="token operator">=</span> fns<span class="token punctuation">[</span>i<span class="token punctuation">]</span>
<span class="token function">fn</span><span class="token punctuation">(</span><span class="token operator">...</span>arguments<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
},
remove = function (key, fn) {
var fns = list[key]
if (!fns) {
return false
} else {
for (var i = fns.length - 1; i >= 0; i–) {
var _fn = fns[i]
if (_fn == fn) {
fns.splice(i, 1)
}
}
}
}
return {
listen,
trigger,
remove
}
})()
export default Event
效果:
转载:https://blog.csdn.net/dyw3390199/article/details/118651237?utm\_medium=distribute.pc\_feed\_v2.none-task-blog-personrec\_tag-6.pc\_personrecdepth\_1-utm\_source=distribute.pc\_feed\_v2.none-task-blog-personrec\_tag-6.pc\_personrec
还没有评论,来说两句吧...