咱们先理解什么是公布-订阅模式,公布-订阅模式它是一种对象间一对多的依赖关系,当一个对象的状态产生扭转时,所有依赖它的对象都将失去状态的告诉。
公布-订阅模式流程如下:
- 订阅者将本人想订阅的事件注册到调度核心;
- 当发布者公布该事件到调度核心时,调度核心执行订阅者注册的事件。
举一个生存中的例子:
张三最近看上一套房子,到售楼处才被告知,该楼盘已售罄。好在售楼MM通知张三,不久后将有一些尾盘推出,开发商正在办理相干手续,手续办好后便能够购买,但到底什么时候好,目前还没有人晓得。
于是张三记下了售楼处的电话,当前每天都会打电话过来询问是不是曾经到了购买工夫。除了张三,还有李四、王五、小明也会每天向售楼处征询这个问题。一个星期过后,售楼MM决定辞职,因为厌倦了每天答复1000个雷同内容的电话。
当然事实中没有这么笨的销售公司,理论是这样的:张三来到之前,将电话号码留在售楼处。售楼MM许可他,新楼盘一推出就马上发信息告诉张三。李四、王五、小明也是一样的,他们的电话号码记录在售楼处的花名册上,新楼盘推出时,售楼MM打开花名册遍历下面的电话号码,顺次发送一条短信告诉他们。
上述例子中,发送短信告诉就是一个公布-订阅模式,张三、王五等购买者都是订阅者,他们订阅房子开售的音讯。售楼处作为发布者,会在适合的时候遍历花名册上的电话号码,顺次给购房者公布音讯。
上述例子存在的益处有:
- 张三不须要每天都打电话过来询问,开发商手续实现后,售楼处会主动发送短信告诉给张三;
- 张三、李四等购买者与售楼处互不烦扰,即便售楼MM辞职也不影响张三、李四等购买者,只有花名册还存在,售楼处就能给购房者公布音讯。
回到代码层面上来,公布-订阅能给咱们带来以下益处:
- 公布、订阅逻辑代码解耦,两者互不影响,订阅逻辑的改变不影响公布逻辑,公布逻辑改变同样不影响订阅逻辑,它们存在一种动静的关系,减少了灵活性;
- 反对简略的播送通信,主动告诉所有曾经订阅过的对象。
理解公布-订阅模式后,再回到mitt身上来。
mitt的介绍与应用
mitt的介绍
mitt是一个公布-订阅模式的库,并且它有9k的Star,长处有:
- 轻量,压缩后体积小于200 bytes;
- 反对通配符“*”事件类型侦听所有事件;
- 与Node的EventEmitter雷同的名称和想法。
mitt的应用
装置:
npm install --save mitt
导入:
// 应用 ES6 模块化
import mitt from 'mitt'
// 应用CommonJs模块化
var mitt = require('mitt')
CDN:
<script src="https://unpkg.com/mitt/dist/mitt.umd.js"></script>
mitt
挂载至全局对象window
。
mitt API办法有:
on
订阅事件;emit
公布事件;off
勾销订阅的事件。
import mitt from 'mitt'
const emitter = mitt()
// 订阅事件
emitter.on('foo', e => console.log('foo', e) )
// 订阅所有的事件
emitter.on('*', (type, e) => console.log(type, e) )
// 公布事件
emitter.emit('foo', { a: 'b' })
// 清空所有事件
emitter.all.clear()
function onFoo() {}
emitter.on('foo', onFoo) // 订阅
emitter.off('foo', onFoo) // 勾销订阅事件
公布-订阅应用场景(包含但不限于):
- 代替传递回调函数的计划,如订阅ajax申请的error、success等事件;
- 页面某个动画,想在动画的每一帧实现之后做一些事,咱们能够订阅一个事件,而后在动画每一帧实现之后公布这个事件;
- 我有A页面、B页面,我在B页面订阅某个列表刷新,当我在A页面点页面返回按钮时,公布该事件触发B页面列表刷新。
这有一个小dome能够点击体验:mitt dome。
实现mitt
mitt非常简单,源码也只有100行而且还是应用了TypeScript的状况下。
我去除掉TypeScript类型,将其批改成javaScript实现:
export default function mitt(all){
//应用Map存储注册的事件
all = all || new Map();
return {
all,
on(type, handler) {
const handlers= all!.get(type);
if (handlers) {
handlers.push(handler);
}
else {
all!.set(type, [handler])
}
},
off(type, handler) {
const handlers = all!.get(type);
if (handlers) {
if (handler) {
const index = handlers.indexOf(handler)
handlers.splice(index > -1 ? index : 0, 1);
}
else {
all!.set(type, []);
}
}
},
emit(type, evt) {
let handlers = all!.get(type);
if (handlers) {
handlers.slice().map((handler) => {
handler(evt);
});
}
//判断是否存在"*" 订阅的事件,"*"注册的事件进行兜底
handlers = all!.get('*');
if (handlers) {
handlers.slice().map((handler) => {
handler(type, evt);
});
}
}
};
}
all
就是一个Map
对象,它用于存储订阅事件。
置信大家了解这几行代码没啥难度。
这样咱们就学会了一个领有9k Star库的所有源码。
当然,咱们还能再给它扩大其余办法,如:once
仅订阅一次,我也写过相似的公布-订阅模式medash/event.ts ,有趣味的同学能够点它看看。
总结
本文先向读者介绍了公布-订阅模式相干实践,再给读者介绍公布-订阅模式社区现成的工具库mitt,最初从mitt的 100行源码中学习到实现公布-订阅模式相干逻辑。
如果我的文章对你有帮忙,您的👍就是对我的最大反对^_^。
往期文章:http://linglan01.cn/about
发表回复