发布订阅模式是一种设计模式,应用广泛,例如DOM2的addEventListener、Vue2的eventBus

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const cb = ()=> {
console.log('触发了')
}

// 监听器
document.addEventListener('myevent', cb,
// 配置项
{
once: false // 是否只执行一次
}
)

// 订阅中心
const myEvent = new Event('myevent')

let count = 1
let timer = null
timer = setInterval(() => {
if(count > 5) {
clearInterval(timer)
// 删除监听
document.removeEventListener(myEvent, cb)
} else {
// 触发器
document.dispatchEvent(myEvent)
}
count++
}, 1000)

手写实现一个发布订阅模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
interface EmitterImpl {
events: Map<string, Set<Function>> // 订阅中心
once: (name: string, cb: Function)=>void // 只触发一次的订阅
on: (name: string, cb: Function)=>void // 订阅
emit: (name: string, ...args: any[])=>void // 发布
off: (name: string, cb: Function)=>void // 取消订阅
}

class Emitter implements EmitterImpl {
events: Map<string, Set<Function>>
constructor() {
this.events = new Map()
}

once(name: string, cb: Function) {
// 包装一个新订阅函数,调用一次后立刻取消
const callback = (...args: any[])=> {
cb(...args)
this.off(name, callback)
}
this.on(name, callback)
}

on(name: string, cb: Function) {
if(this.events.has(name)) {
this.events.get(name)?.add(cb)
} else {
this.events.set(name, new Set([cb]))
}
}

emit(name: string, ...args: any[]) {
let set = this.events.get(name)
if(set) {
set.forEach(cb=> {
cb(...args)
})
}
}

off(name: string, cb: Function) {
let set = this.events.get(name)
if(set) {
set.delete(cb)
}
}
}

const bus = new Emitter()

const cb = (b: boolean, n1: number, n2: number, s: string)=> {
console.log('触发了', b, n1, n2, s)
}

bus.on('msg', cb)
bus.on('msg', ()=> {console.log('12321')})
bus.once('msg', ()=> {console.log('once')})

let count = 0
setInterval(()=> {
if(count > 2) {
bus.off('msg', cb)
}
bus.emit('msg', true, 114, 514, 'yajue')
count++
}, 1000)