前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >通过EventBus实现发布与订阅模式

通过EventBus实现发布与订阅模式

作者头像
kifuan
发布2022-10-24 16:41:31
发布2022-10-24 16:41:31
30600
代码可运行
举报
文章被收录于专栏:随便写写-kifuan随便写写-kifuan
运行总次数:0
代码可运行

源码

点击这里前往Github获取本文源码。

背景

后注: 发布-订阅模式属于设计模式中的行为型模式,基本上和观察者模式相同,至于具体定义存在争议,这里不进行讨论。

Vue中,我们经常通过全局事件总线进行简单的组件间通信,那么究其原理其实并不难,本文就来着手实现一个这样的功能。

实现

代码不是很难,直接贴出来,后文会解释这些代码的作用:

代码语言:javascript
代码运行次数:0
复制
class EventBus {
    callbacks = {}

    on(event, callback) {
        // 第一处标记,下面会提到
        const callbacks = this.callbacks[event] ||= new Set()
        callbacks.add(callback)
        return this
    }

    once(event, callback) {
        const actual = (...args) => {
            callback(...args)
            this.remove(event, actual)
        }
        this.on(event, actual)        
        return this
    }

    emit(event, ...args) {
        this.callbacks[event]?.forEach(callback => {
            callback(...args)
        })
        return this
    }

    remove(event, callback = undefined) {
        if (callback) {
            this.callbacks[event]?.delete(callback)
        } else {
            delete this.callbacks[event]
        }
        return this
    }
}

首先观察到所有函数都返回了this,由此我们可以进行链式调用。下面逐一解释:

  • on(event, callback) 我们把传入的callback添加到this.callbacks[event]这个集合中,为了以后触发事件的时候被调用。 注意到我们在第一处标记,通过||=短路赋值this.callbacks[event]一个空集合,并且把这个赋值表达式的结果给一个局部变量。并且由于集合是引用类型,之后我们就可以通过操作这个局部变量来影响到原数据了。
  • once(event, callback) 使用once添加的回调函数只会被调用一次,方法体中我们把传入的函数包装了一层。这个函数被调用后会通过this.remove(event, actual)删除本身,达到只调用一次的效果。
  • emit(event, ...args) 触发指定的事件,并且传入参数,方法体内部通过forEach遍历所有的回调函数。
  • reomve(event, callback = undefined) 删除指定的事件。如果没有指定是哪一个回调,就把整个事件对应的回调函数都删除掉。

使用

通过下列代码测试这个简易框架的正确性:

代码语言:javascript
代码运行次数:0
复制
const bus = new EventBus()

bus.on('foo', () => {
    console.log('foo 1')
}).on('foo', () => {
    console.log('foo 2')
}).emit('foo')
// foo 1
// foo 2

bus.remove('foo')
    .emit('foo')
// it will do nothing


bus.on('bar', n => {
    console.log('bar:', n)
}).once('bar', n => {
    console.log('bar once:', n)
}).emit('bar', 3)
// bar: 3
// bar once: 3

bus.emit('bar', 3)
// bar: 3

读者可以到控制台试验一下,看看是否是预期效果。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 源码
  • 背景
  • 实现
  • 使用
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档