Skip to content

Instantly share code, notes, and snippets.

@MrKou47
Last active November 27, 2017 02:40
Show Gist options
  • Save MrKou47/0e01ef42882cdf1c80d996fdbef9c290 to your computer and use it in GitHub Desktop.
Save MrKou47/0e01ef42882cdf1c80d996fdbef9c290 to your computer and use it in GitHub Desktop.
发布/订阅模式
function PubSub() {
this.eventList = [];
}
PubSub.prototype.subscrible = function (eventName, callback) {
const currentEvent = this.eventList.find(obj => obj && obj.name === eventName);
if (currentEvent) {
this.eventList.find(obj => obj && obj.name === eventName).callback = callback;
} else {
this.eventList.push({ name: eventName, callback, });
}
};
PubSub.prototype.publish = function (eventName, args) {
const currentEvent = this.eventList.find(obj => obj && obj.name === eventName);
if (currentEvent) currentEvent.callback(args);
};
PubSub.prototype.unSubscrible = function (eventName) {
this.eventList = this.eventList.filter(eObj => eObj.name !== eventName);
}
/**
* 原型继承
* @param {*} currentClass
* @param {*} targetClass
*/
function inheritClass(currentClass = {}, targetClass) {
for (var name in targetClass.prototype) {
currentClass.prototype = Object.assign({}, targetClass.prototype, currentClass.prototype);
// Object.defineProperty(currentClass, name, targetClass.prototype[name]);
}
}
// 订阅一个事件
pubSub.subscrible('start_class', function (time) {
console.log(`要上课啦 上课时间为 ${time}`);
});
// // 发布一个事件 并携带参数
pubSub.publish('start_class', new Date());
pubSub.unSubscrible('start_class'); // 取消订阅事件
pubSub.publish('start_class', new Date('2017/07/07')); // 无效
function Person() {
PubSub.call(this);
}
inheritClass(Person, PubSub); // 让 Person 同样具有发布/订阅事件的能力
const Bob = new Person();
Bob.subscrible('sleep', function (when) {
console.log(`people want sleep!!! ${when}`);
});
Bob.publish('sleep', 'now!!');
@MrKou47
Copy link
Author

MrKou47 commented Nov 27, 2017

如何实现一个发布订阅模型

我们的目的是,实现一个事件驱动的控制器,通过 定义事件(包括事件的名称,和触发事件后会发生什么事情)和触发事件,来控制我们代码的运行过程。 好处是: 定义一个事件,能够在任意时间触发回调函数。

举例:PandaTV 是如何实现订阅的?

比如,我在看托马斯直播,然后这个狗贼杀人之后说“大家订阅走一走”,小王听了,点了订阅, 当他点击了订阅按钮后,发送请求到pandatv服务端,服务器上维护了一个数组,那服务器接收了请求之后,调用了 subscribe 方法。比如 subscribe('tuomasi', 'xiaowang')。那下次托马斯点击“开播”按钮的时候,他就触发了 publish('tuomasi') 事件,然后服务器就向小王手机上发了短信,说托马斯开播啦。这就是一个订阅的例子。

首先定义包含所有事件的数组

此数组包含了所有我们定义的事件以及事件的回调函数。

const eventList = [];

接着编写定义事件的方法 —— subscribe

那我们可以通过此方法定义事件和事件的回调,定义后将定义的事件 push 到我们刚才定义的数组中

**注意: ** 如果我们在定义事件的时候,之前已经有了相同名字的事件,那我们就需要把之前我们定义的事件的回调函数替换为我们当前的、新的回调函数。

function subscribe(eName, eCb) {
  // 需要判断一下保存我们定义的事件的数组中有没有重名的
  if () {

  } else {
    eventList.push({
       name: eName,
       callback: eCb,
    });
  }
}

触发事件(也叫做发布事件)的方法 —— publish

我们通过此方法,提供一个事件的名称,在我们保存事件的数组 eventList 中查找我们想要触发的事件,找到后,执行此事件的回调函数。

function publish(eName, ...params) {
  // 从 eventList 中找到我们需要的事件,把参数传递给它
  
}

退订方法

我们通过此方法来删除 eventList 中的事件,这样我们在调用 publish 方法的时候就不会触发了

function unsubscribe(eName) {
  // 通过 findIndex 找到指定的事件的 index, 然后通过 splice 删除它
}

我们再回到之前的pandaTv的问题,大家应该发现,我们不是说 subscribe 方法只有一个回调么,那小王订阅了之后小明订阅了怎么办?
实际上这个方法应该是,用户订阅,和主播开播, 这两个服务端已经写好了这两个事件。意思就是,用户触发的是一个通用的方法,比如之前服务器已经写好了
subscribe('订阅主播', function (主播名, 用户id) { 在这里方法里面,向数据库里面、此主播的订阅的观众的数组里面push小王的用户id }),那用户点击订阅后实际上就是,比如小王的用户id是666, 那在服务器端就是触发了一个这个 ‘订阅主播’ 的事件: publish('订阅主播', '托马斯', '666'),然后服务端同时也定义了一个开播的事件,比如 subscribe('开播',function(主播名) { 在这个方法里面,服务器去找此主播的所有订阅观众,然后给每一个人都发短信 })。这就是实现最简单的订阅的过程。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment