发布订阅模式

54 阅读1分钟

简单示例

image.png

npm init 
tsc --init

实时将 ts 转为 js,并引入 到 html。

tsc -w 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script src="index.js"></script>
</body>
</html>

一个简单的发布订阅:

document.addEventListener('clickkk', ()=> {
    console.log('clickkk')
}, {
    once: true  // 只触发一次
})
// 创建一个事件
const e = new Event('clickkk')  // 订阅中心
// EventTarget.dispatchEvent() 触发事件
// element、document 和 window 等DOM节点都是EventTarget接口(类)的实例
document.dispatchEvent(e)
document.dispatchEvent(e)

手写发布订阅模式

/**
 * 订阅发布模式
 * - once
 * - on
 * - emit
 * - off
 * 订阅中心 Map(事件名称, 事件处理函数集合)
 */
interface I {
    events: Map<string, Function[]>
    once: (event: string, callback: Function) => void // 事件只触发订阅器
    on: (event: string, callback: Function) => void // 订阅事件
    off: (event: string, callback: Function) => void // 取消订阅
    emit: (event: string, ...args: any[]) => void // 触发事件(发布)
}

class EventEmitter implements I {
    events: Map<string, Function[]>

    constructor() {
        this.events = new Map()
    }

    once(event: string, callback: Function) {
        // 创建一个自定义函数 通过 on 触发 之后立即回收
        const fn = (...args: any[]) => {
            callback(...args)
            this.off(event, fn)
        }
        this.on(event, fn)
    }

    off(event: string, callback: Function) {
        const callbackList = this.events.get(event)
        if (callbackList) {
            callbackList.splice(callbackList.indexOf(callback), 1)
        }
    }

    emit(event: string, ...args: any[]) {
        const callbackList = this.events.get(event)
        if (callbackList) {
            callbackList.forEach(cb => {
                cb(...args)
            })
        }
    }

    on(event: string, callback: Function) {
        // 事件是否存储
        if (!this.events.has(event)) {
            this.events.set(event, [callback])
        } else {
            const callbackList = this.events.get(event)
            callbackList && callbackList.push(callback)
        }
    }
}

const bus = new EventEmitter()
const fn = (b: boolean, n: number) => {
    console.log('fn', b, n)
}
// bus.on('message', fn)
bus.once('message', fn)
bus.emit('message', false, 1)
bus.emit('message', false, 1)
bus.emit('message', false, 1)
bus.emit('message', false, 1)