“这是我参与8月更文挑战的第17天,活动详情查看:8月更文挑战”
前言
在面试高级前端时,往往会遇到一些关于设计模式的问题,每次都回答不太理想。恰逢8月更文挑战的活动,准备用一个月时间好好理一下关于设计模式方面的知识点,给自己增加点面试的底气。
在上篇文章 中实现了一个简单的发布-订阅模式,但是其中有两个很严重的缺点,每个发布者都要有添加订阅者 、发布消息、移除订阅者的方法,还要需要一个缓存订阅者的列表,这样严重浪费内存资源,另外一个是订阅者要知道发布者才能订阅,它们之间存在一定的耦合性。
所以发布者和订阅者之间得需要一个中介,本文就来实现这个中介,这样发布者可以不必拥有添加订阅者 、发布消息、移除订阅者的方法、缓存订阅者的列表,把这些都交给中介。订阅者不需要了解消息来自哪个发布者,发布者也不知道消息会推送给哪些订阅者,中介会把订阅者和发布者联系起来。
基于中介的发布-订阅
var Event = (function () {
let clientList = {};// 缓存订阅者列表
const listen = function (key, fn) {// 添加订阅者 其中key为订阅者的标识
if (!clientList[key]) {
clientList[key] = [];
}
clientList[key].push(fn);
};
const trigger = function () {
// 通过`trigger`发布方法的第一参数来获取订阅者的标识
const key = Array.prototype.shift.call(arguments);
const fns = clientList[key];
if (!fns || fns.length === 0) {
return false;
}
for (let i = 0, fn; fn = fns[i++];) {
fn.apply(this, arguments);
}
};
const remove = function (key, fn) {
const fns = clientList[key];
if (!fns) {
return false;
}
if (!fn) {
fns && (fns.length = 0);
} else {
for (let l = fns.length - 1; l >= 0; l--) {
const _fn = fns[l];
if (_fn === fn) {
fns.splice(l, 1);
}
}
}
};
return {
listen: listen,
trigger: trigger,
remove: remove
}
})();
订阅者通过Event.listen
来订阅消息:
Event.listen('土豪金', function (price) { // 小王订阅消息
console.log(`手机到货了,颜色是土豪金,价格是${price}元,快来购买吧!`)
});
发布者通过Event.trigger
来发布消息:
Event.trigger('土豪金', 9999); // 输出:手机到货了,颜色是土豪金,价格是9999元,快来购买吧!
JavaScript中的发布-订阅模式
在JavaScript中,可以用注册回调函数的形式来简单地实现的发布-订阅模式,假如用类的方式来实现发布-订阅模式,还要把订阅者对象传入发布者对象中,同时订阅者对象还要提供一个更新 updata 的方法,供发布者在某个时候调用。
另外发布-订阅模式,还有推模型还是拉模型的区分,推模型是指在事件发生时,发布者一次性把所有更改的状态和数据都推送给订阅者。拉模型是指发布者仅仅通知订阅者我已经发布了,提供一些公开的接口供订阅者来主动拉取数据,模型的好处是可以让订阅者按需获取信息。
而在JavaScript中,arguments可以很方便地表示函数所接收的参数,所以在JavaScript中一般都会选择推模型,使用apply
方法把所有参数都推送给订阅者。
优点和缺点
发布-订阅模式的优点非常明显,一为时间上的解耦,二为对象之间的解耦。
发布-订阅模式也有缺点,创建订阅者本身要消耗一定的时间和内存,而且当你订阅一个消息后,也许此消息最后都未发生,但这个订阅者会始终存在于内存中。另外,发布—订阅模式虽然可以弱化对象之间的联系,但如果过度使用的话,对象和对象之间的必要联系也会被隐藏起来,当多个发布者和多个订阅者互相关联时,出现BUG将会很难跟踪和修复。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!