Kasan Blog

源码

手写发布订阅:

思路:

写一个on ,用于订阅监听事件,on(‘事件名’,fn) 把所有订阅了该事件名的fn放到一起,当发布该事件时,遍历执行这些fn,实现事件发布

写一个emit,用于发布事件,当emit触发时,所有订阅了此事件的订阅者将会触发事件(触发需要调用的函数)

写一个off,用于取消订阅事件


实现效果: 订阅者可以通过 on 函数订阅自定义事件,并上传一个发布时所触发的函数

发布者可以对 任意自定义事件 进行发布,

意思就是订阅了此事件的订阅者,可以执行上传的函数了,执行函数的顺序是,先订阅的先执行

并且发布者还能传参数给 订阅者的函数使用


中央调度中心

// 这个xxx.js 是订阅发布的逻辑,导出此逻辑给其它模块引用
export const eventHub = {
    // map 是消息队列,存储所有的订阅者,发布时,先订阅的先执行
    map: {
        // click: [f1 , f2 , ...]
        // click1:[f1 , f2 , ...]
    },
    on: (name, fn) => { // name 是监听的事件名, fn 是监听的事件被发布后触发的函数,on是指订阅
        //如果没有此事件就新建一个空数组以存储新事件
        eventHub.map[name] = eventHub.map[name] || []
        eventHub.map[name].push(fn)
    },
    emit: (name, data) => { // name 是需要发布的事件名,
        //data 会传给所有订阅了此事件的订阅者,订阅了此事件的订阅者会接收data并传给 on 的 fn 函数
        const q = eventHub.map[name]
        if (!q) {console.error('不存在此事件'); return}
        q.map(f => f.call(null, data))
        return undefined
    },
    off: (name, fn) => { // 取消订阅
        const q = eventHub.map[name]
        if (!q) { return }
        const index = q.indexOf(fn)
        if (index < 0) {  console.error('取消订阅失败'); return }
        q.splice(index, 1)
        console.log('取消订阅成功')
    }
}

订阅者1

import {eventHub} from './xxx' 


// main.js 订阅了同一个监听事件,但是触发的函数不同
eventHub.on('click', (data)=>{console.log('main.js的click事件被触发:' + data + '这句话代表不同的函数')})
eventHub.on('click', (data)=>{console.log('main.js的click事件被触发:' + data)})


// 如果订阅的事件不被发布,就不会被执行所传的函数
eventHub.on('upPage', (data)=>{console.log('main.js的upPage事件被触发:' + data)})

订阅者2

import {eventHub} from './xxx' 

const fn1 = (data)=>{
    console.log("test.js函数被触发" + data)
}

// test.js 订阅了一个名为click的事件
eventHub.on('click', fn1)
eventHub.off('click', fn1)

setTimeout(() => {  
    // 在一秒后发布此事件,所有订阅了click事件的订阅者
    //将会接收到来自emit传的data('kasan')作为形参并传给订阅时所传的函数(fn1)
    eventHub.emit('click', 'kasan')
}, 1000);

console.log(eventHub)


实际运行代码图没有下面的 upPage 因为被取消了