JS发布订阅模式
介绍
在 vue
开发中,经常会用到事件传递,例如 eventBus
,我们可以使用 on
和 emit
方法去触发需要的事件.
定义
发布-订阅模式其实是一种对象间一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都将得到状态改变的通知。订阅者( Subscriber
)把自己想订阅的事件注册( Subscribe
)到调度中心( Event Channel
),当发布者( Publisher
)发布该事件( Publish Event
)到调度中心,也就是该事件触发时,由调度中心统一调度( Fire Event
)订阅者注册到调度中心的处理代码。 例如以下在 vue
中的使用
// 封装成工具库eventBus
import Vue from 'vue'
let bus = new Vue()
Vue.prototype.$eventBus = bus
export default bus
// 页面使用
import Bus from './commom/eventBus'
Bus.$emit('test', null)
Bus.$on('test', this.doSomeThing)
实现
以上是 vue
集成了功能.同样的,我们可以用 es6
实现. ::: warning 思路
创建一个对象
在该对象上创建一个缓存列表(调度中心)
on
方法用来把函数fn
都加到缓存列表中(订阅在注册事件到调度中心)emit
方法取到arguments
里第一个当做event
,根据event
值去执行对应缓存列表中的函数(发布者发布事件到调度中心,调度中心处理代码)off
方法可以根据event
值取消订阅(取消订阅) :::
// 代码
let eventEmitter = {
// 缓存列表
list: {},
// 订阅
on (event, fn) {
// 如果没有event值,就给event创建个缓存列表
// 如果有对应的event值,把fn添加到对应event的缓存列表里
(this.list[event] || (this.list[event] = [])).push(fn)
return this
},
// 监听一次
once (event, fn) {
// 先绑定,调用后删除
function on () {
this.off(event, on)
fn.apply(this, arguments)
}
on.fn = fn
this.on(event, on)
return this
},
// 取消订阅
off (event, fn) {
let fns = this.list[event]
// 如果缓存列表中没有对应的fn,返回false
if (!fns) return false
if (!fn) {
// 如果fn不存在,就会将event值对应缓存列表中的fn都清空
fns && (fns.length = 0)
} else {
// 如果有fn, 遍历缓存列表,看看传入的fn与那个函数相同,如果相同就直接从缓存列表中删除
let cb
let cbLen = fns.length
for (let i = 0; i < cbLen; i++) {
cb = fns[i]
if (cb === fn || cb.fn === fn) {
fns.splice(i, 1)
break
}
}
}
return this
},
// 发布
emit () {
// 第一个参数对应的event值,直接用数组的shift方法取出
let event = [].shift.call(arguments)
let fns = [...this.list[event]]
// 如果缓存列表里没有fn就返回false
if (!fns || fns.length === 0) {
return false
}
// 遍历event值对应的缓存列表,依次执行fn
fns.forEach(fn => {
fn.apply(this, arguments)
})
return this
}
}
// 测试
function user1 (content) {
console.log('用户1订阅了: ', content)
}
function user2 (content) {
console.log('用户2订阅了: ', content)
}
function user3 (content) {
console.log('用户3订阅了: ', content)
}
function user4 (content) {
console.log('用户4订阅了: ', content)
}
// 订阅
eventEmitter.on('article1', user1)
eventEmitter.on('article1', user2)
eventEmitter.on('article1', user3)
// 取消user2方法的订阅
eventEmitter.off('article1', user2)
eventEmitter.once('article2', user4)
// 发布
eventEmitter.emit('article1', 'JS 发布-订阅模式')
eventEmitter.emit('article1', 'JS 发布-订阅模式')
eventEmitter.emit('article2', 'JS 观察者模式')
eventEmitter.emit('article2', 'JS 观察者模式')
参考
Last updated
Was this helpful?