介绍


在《Javascript设计模式》书中定义:Subscribe/Publish模式使用了一个主题/事件通道,这个通道介于希望接收到通知(订阅者)的对象和激活事件的对象(发布者)之间。该事件系统允许代码定义应用程序的特定事件,该事件可以传递自定义参数,自定义参数包含订阅者所需要的值。其目的是避免订阅者和发布者产生依赖关系。

优点:

  • 松耦合
  • 扩展性强
  • 灵活度高
  • 易于测试

缺点:

  • 由于订阅者和发布者之间动态关系,很难跟踪依赖更新。

个人理解


故事:小王和小李经常在同一个前端公众号阅读前端文章。小王爱看JS,他订阅了公众号JS板块,而小李爱看NODEJS,他订阅NODEJS板块。公众号一旦发布了新的文章就会通知到他们。
先看下故事中所提到的人物。发布者是前端公众号,订阅者是小王和小李,有新文章会推送给小王和小李。

代码实现


  1. 定义发布者。
  2. 发布者添加缓存列表,用来存放订阅者的回调函数以便通知到订阅者。
  3. 发布者发布消息时,遍历缓存列表,依次触发里面的回调函数。
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实现


通过jquery callbacks实现发布订阅模式

版权声明:本文为博主原创文章,转载请添加原文地址
暂无评论