介绍
在《Javascript设计模式》书中定义:Subscribe/Publish模式使用了一个主题/事件通道,这个通道介于希望接收到通知(订阅者)的对象和激活事件的对象(发布者)之间。该事件系统允许代码定义应用程序的特定事件,该事件可以传递自定义参数,自定义参数包含订阅者所需要的值。其目的是避免订阅者和发布者产生依赖关系。
优点:
- 松耦合
- 扩展性强
- 灵活度高
- 易于测试
缺点:
- 由于订阅者和发布者之间动态关系,很难跟踪依赖更新。
个人理解
故事:小王和小李经常在同一个前端公众号阅读前端文章。小王爱看JS,他订阅了公众号JS板块,而小李爱看NODEJS,他订阅NODEJS板块。公众号一旦发布了新的文章就会通知到他们。
先看下故事中所提到的人物。发布者是前端公众号,订阅者是小王和小李,有新文章会推送给小王和小李。
代码实现
- 定义发布者。
- 发布者添加缓存列表,用来存放订阅者的回调函数以便通知到订阅者。
- 发布者发布消息时,遍历缓存列表,依次触发里面的回调函数。
var qianduan7 = {}; // 定义发布者(前端公众号)
qianduan7.clientList = []; // 缓存列表(小王和小李的回调函数)
// 添加订阅者
qianduan7.listen = function(fn) {
this.clientList.push(fn); // 订阅消息添加至缓存列表
}
// 发布消息, 依次通知订阅者
qianduan7.trigger = function() {
var fns = this.clientList; // 取出该消息对应的回调函数集合
for(var i = 0; i< fns.length; i++) {
fns[i].apply(this, arguments); // arguments是发布消息时附送的参数
}
}
// 小王订阅的消息
qianduan7.listen(function(type) {
console.log(`小王订阅的${type}文章`);
});
// 小李订阅的消息
qianduan7.listen(function(type) {
console.log(`小李订阅的${type}文章`);
});
// 公众号发布消息
qianduan7.trigger('nodejs');
qianduan7.trigger('js');
运行结果:
我们发现发布小王喜欢JS但收到了NODEJS文章,小李喜欢NODEJS但收到了JS文章。实际上小王只想看JS文章,而小李只想看NODEJS文章。
改造方案:在订阅公众号时,我们需要告诉它我们想订阅的文章类型。此处还友情客串了下小王的儿子,以便理解。
var qianduan7 = {}; // 定义发布者(前端公众号)
qianduan7.clientList = []; // 缓存列表(小王和小李的回调函数)
// 添加订阅者
qianduan7.listen = function(key, fn) {
if(!this.clientList[key]) { // 若缓存列表没有该类型的消息,初始化消息
this.clientList[key] = [];
}
this.clientList[key].push(fn); // 订阅消息添加至缓存列表
}
// 发布消息, 依次通知订阅者
qianduan7.trigger = function() {
var key = Array.prototype.shift.call(arguments); // 取出消息类型
var fns = this.clientList[key]; // 取出该消息对应的回调函数集合
if(!fns || fns.length == 0) { // 若订阅列表没有该类型的回到函数,则返回
return false;
}
for(var i = 0; i< fns.length; i++) {
fns[i].apply(this, arguments); // arguments是发布消息时附送的参数
}
}
// 小王订阅的js
qianduan7.listen('js', function(data) {
console.log('小王收到的内容:' + data);
});
// 小王儿子订阅的js
qianduan7.listen('js', function(data) {
console.log('小王儿子收到的内容:' + data);
});
// 小李订阅的nodejs
qianduan7.listen('nodejs', function(data) {
console.log('小李收到的内容:' + data);
});
// 公众号发布消息
qianduan7.trigger('js', 'js创始人是Brendan Eich.');
qianduan7.trigger('nodejs', 'nodejs作者是Ryan Dahl.');
运行结果:
实际应用
// 订阅首页成功状态
qianduan7.listen('success', function(data) {
// 是否需要登录
isLogin(data);
});
// 订阅首页成功状态
qianduan7.listen('success', function(data) {
// 渲染页面模块A
renderA(data);
});
// 订阅首页成功状态
qianduan7.listen('success', function(data) {
// 渲染页面模块B
renderB(data);
});
$.get('http://www.qianduan7.com/index', function(data) {
qianduan7.trigger('success', data); // 请求成功后发布消息
});
jquery callbacks实现
版权声明:本文为博主原创文章,转载请添加原文地址 https://www.qianduan7.com/javascript/subscribe-publish.html