js-发布订阅模式

26次阅读

共计 1303 个字符,预计需要花费 4 分钟才能阅读完成。

JavaScript 中有五种异步编程的方式

  • 1. 回调函数
    2. 事件监听
    3. 发布订阅
    4.Promise 对象
    5.Generator 函数
 发布 / 订阅 模式
比方说淘宝购物,小红在淘宝上看到一双鞋,但是卖光了,小红联系卖家什么时候有货,卖家告诉小红需要等一星期,卖家说如果喜欢可以等有货的时候
再通知你,所以小红收藏了该店铺,但是同时,小明,小花也喜欢这款鞋,也收藏了改店铺,等鞋子到了就会依次通知小红,小明,小花。这里卖家属于发布者,小红,小明属于订阅者
function Public(){this.handles = {}
    // 订阅事件
    this.addEventListener  = function(eventType,fn){if(!(eventType in this.handles)){this.handles[eventType] = []}
        this.handles[eventType].push(fn)
        console.log(this.handles)
        return this;
    },
    // 触发事件
    this.dispatchEvent = function(eventType){var handlerArgs = Array.prototype.slice.call(arguments,1);
        if(!this.handles[eventType]){throw Error("该名称未发布")
        }
        for(var i=0;i<this.handles[eventType].length;i++){this.handles[eventType][i].apply(this,handlerArgs)
        }
        return this;
    }
    // 删除订阅事件
    this.removeEventListener = function(eventType,handler){var currentEvent = this.handles[eventType];
        if(!handler){delete(this.handles[eventType])
            return
        }
        if (currentEvent) {const index = this.handles[eventType].findIndex(ele => ele.name === handler.name)
            this.handles[eventType].splice(index,1)
        }
        return this;
    }
}

var publish = new Public();
publish.addEventListener("xiaohong",function tellHong(data){console.log(`${data}`)
})
publish.addEventListener("xiaoming",function tellMing(data){console.log(`${data}`)
})
publish.dispatchEvent("xiaohong","小红你的鞋子到了")
publish.dispatchEvent("xiaoming","小明你的鞋子到了")
publish.removeEventListener("xiaohong")

正文完
 0

JS 发布订阅模式

26次阅读

共计 1362 个字符,预计需要花费 4 分钟才能阅读完成。

首先声明,本文并非原创。原文请点击这里,本文是在原文的基础上加入一些自己的一些东西,方便以后自己理解与查看。
发布订阅模式
事件发布 / 订阅模式 (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() {
// 取第一个参数,作为 eventType
var eventType = Array.prototype.shift.call(arguments);
// 获取事件数组
var arr = this.obj[eventType];
var len = arr.length;
// 循环数组,一次执行其中的函数
for(var i=0;i<len;i++) {
// 直接调用 arr[i],其 this 指向为 undefined(严格模式下)
// 因此用 apply 将 this 指向 arr[i]
// 数组 shift 函数取出第一个参数,将剩下的参数传入函数中
arr[i].apply(arr[i],arguments)
}
}

var ev = new Event()
ev.on(‘click’,function(a) {// 订阅
console.log(a)
})

ev.emit(‘click’,1) // 发布
以上代码只能实现先订阅,再发布。直接发布就会报错。如何实现可以先发布,然后订阅?
var Event = function() {
this.obj = {};
this.cacheList = [];
}

Event.prototype.emit = function() {
const args = arguments; // 函数参数
const that = this; //this 指向, 保持 cache 函数的 this 指向
function 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 函数中参数和 that 的引用
}

Event.prototype.on = function(eventType,fn) {
if(!this.obj[eventType]) {
this.obj[eventType] = []
}
this.obj[eventType].push(fn)
// 在订阅函数中执行 emit 函数中缓存的函数
for (let i = 0; i < this.cacheList.length; i++) {
this.cacheList[i]()
}
}

改成这样后就实现了先发布函数,再订阅的过程。但是也只能先发布,然后再订阅,反过来就行不通。

正文完
 0