事件发布/订阅模式 (PubSub) 在异步编程中帮助我们完成更松的解耦, 甚至在 MVC、MVVC 的架构中以及设计模式中也少不了发布-订阅模式的参与。
优点: 在异步编程中实现更深的解耦
缺点: 如果过多的使用发布订阅模式, 会增加维护的难度
var Event = function() {this.obj = {}}Event.prototype.on = function(eventType, fn) {if (!this.obj[eventType]) {this.obj[eventType] = []}this.obj[eventType].push(fn)}Event.prototype.emit = function() {var eventType = Array.prototype.shift.call(arguments)var arr = this.obj[eventType]for (let i = 0; i < arr.length; i++) {arr[i].apply(arr[i], arguments)}}var ev = new Event()ev.on('click', function(a) { // 订阅函数console.log(a) // 1})ev.emit('click', 1) // 发布函数
考虑以下场景:
$.ajax('', () => {// 异步订阅函数逻辑})// 在其他地方执行发布函数, 此时并不能保证执行发布函数的时候, 订阅函数已经执行
我们需要实现这样的逻辑:
var ev = new Event()ev.emit('click', 1)ev.on('click', function(a) {console.log(a) // 1})
目标明确后, 来着手实现它:
var Event = function() {this.obj = {}this.cacheList = []}Event.prototype.on = function(eventType, fn) {if (!this.obj[eventType]) {this.obj[eventType] = []}this.obj[eventType].push(fn)for (let i = 0; i < this.cacheList.length; i++) {this.cacheList[i]()}}Event.prototype.emit = function() {const arg = argumentsconst that = thisfunction cache() {var eventType = Array.prototype.shift.call(arg)var arr = that.obj[eventType]for (let i = 0; i < arr.length; i++) {arr[i].apply(arr[i], arg)}}this.cacheList.push(cache)}
以上代码实现思路就是把原本在 emit 里触发的函数存到 cacheList, 再转交到 on 中触发。从而实现了发布函数先于订阅函数执行。