发布-订阅模式

发布—订阅模式,它定义了一种一对多的依赖关系,当发布者发出一种消息时,所有订阅该消息的任务(回调函数)都将开始执行。
订阅是希望在某消息或事件发生时可以执行对应的任务;发布指对外广播告知消息已经到达,所有订阅了该消息的任务可以执行了。
在传统的发布-订阅模式中,如Java,通常需要把订阅者对象自身当成引用传入发布者对象中,而在 JavaScript 中,使用回调函数的形式来代替订阅者。
nodejs中的on/emit也是采用这种模式在模块间通信的。
优点:在异步编程中代替传递回调函数;模块间的通信变成松耦合。
  // 发布者对象
  var Pubsub = function () {
    // Storage for topics that can be broadcast or listened to
    this.topics = {};
    // A topic identifier
    this.subUid = -1;
  }
  Pubsub.prototype = {
    // Subscribe to events of interest with a specific topic name and a callback function, to be executed
    // when the topic/event is observed
    subscribe: function (topic, func) {
      if (!this.topics[topic]) {
        this.topics[topic] = [];
      }
      var token = ( ++this.subUid ).toString();
      this.topics[topic].push({
        token: token,
        func: func
      });
      return token;
    },
    // Publish or broadcast events of interest with a specific topic name and arguments
    publish: function (topic, args) {
      if (!this.topics[topic]) {
        return false;
      }
      var subscribers = this.topics[topic];
      subscribers.forEach(function (el) {
        el.func(topic, args)
      });
      return this;
    },
    // Unsubscribe from a specific topic, based on a tokenized reference to the subscription
    unsubscribe: function (token) {
      for (var m in this.topics) {
        if (this.topics[m]) {
          this.topics[m] = this.topics[m].filter(function (el) {
            return el.token !== token;
          });
          return token;
        }
      }
      return this;
    }
  }

使用:

//  消息/时间发发生时,执行所有订阅该消息的任务
 var store = new Pubsub();
  store.subscribe('available', function (data) {
    console.log('有货了');
  });
  store.subscribe('available', function (data) {
    console.log('有货了');
  });
  setTimeout(() => store.publish('available',20), 2000)

解耦模块,方便扩展:

  $.ajax('http:www.example.com/login', function (data) {
    header.setAvatar(data.avatar);
    message.refresh();  // 刷新消息
    cart.refresh();     // 刷新购物车
    address.refresh();   // 新增刷新地址时耦合性太强,不好维护
  });

  // 更改为发布-订阅模式:
  //登录模块只需要发布登录成功的消息,不用了解业务方的内部实现及目的。而业务方接受到消息之后,就会开始进行各自的业务处理。
  var login = new Pubsub();
  var header = (function () {   // header 模块
    login.subscribe('loginSuccess', function (data) {
      header.setAvatar(data.avatar);
    });
    return {
      setAvatar: function (data) {
        console.log('设置头像');
      }
    }
  })();
  $.ajax('http:www.example.com/login', function (data) {
    login.publish('loginSuccess', data);   // 发布登录成功的消息
  });
View Code

 

posted @ 2017-09-24 21:57  开发之路  阅读(498)  评论(0编辑  收藏  举报