发布—订阅模式,它定义了一种一对多的依赖关系,当发布者发出一种消息时,所有订阅该消息的任务(回调函数)都将开始执行。
订阅是希望在某消息或事件发生时可以执行对应的任务;发布指对外广播告知消息已经到达,所有订阅了该消息的任务可以执行了。
在传统的发布-订阅模式中,如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); // 发布登录成功的消息 });