近日沉迷搬砖(偷懒),都没什么时间更新文章了,砖搬的差不多了赶紧回来写点小玩意~

依旧是背景介绍,我们在网购的时候都填过地址吧,一般点击编辑地址的时候都会跳到新的页面,那么问题来了,我们编辑好提交之后,怎么把数据给回上一个页面呢?

如果我们遇到上面的情景会怎么解决呢?方案倒不少,storage、状态管理甚至暂存到全局。今天我想介绍的方案是EventBus,也就是我们常说的事件总线,也可以认为是发布/订阅模式,废话不多说,直接进入正题。

用了EventBus之后有何不同?

引入事件总线之后,在下单页跳转至地址编辑页之前,我们可以订阅一个事件例如:订阅一个key为”address”的事件,并规定事件触发后该执行的函数,比如将获取到的信息展示出来。

在地址编辑页完成编辑后,我们会发布一个key为”address”的事件,并传递一些参数(例如此处应传递地址信息)。事件发布后,会触发订阅通道中key为”address”的事件回调。这样就完成了我们需要的数据传递并展示。

如何实现一个简易的EventBus

首先我们看张示意图,对EventBus有个更直观的了解。

x

不难发现,我们完成一个简易的EventBus其实只需这么3个方法 – on/emit/off

  • 事件订阅 – on

x

首先构造一个EventBus函数,然后给它赋予on方法。该方法可传入三个值,key/cb/isKeep分别代表订阅的键值、事件回调以及是否持久化订阅。

实际情况中,我们很多时候的事件订阅都是一次性动作,所以我们的订阅行为默认是一次性的并且isKeep也不作为必备参数。

但是key则不一样,如果没有key的传入这个方法是完全没有意义的,所以我们将key值设为必备的参数。获得key后,首先会在events对象中查看是否已存在,如果没有则为这个key新增一个属性并赋予空组数,最后把事件回调以及是否持久化作为对象传入数组中。

  • 取消订阅 – off

x

如果我们不想再订阅某个事件,我们就需要一个取消订阅的方法,因为我们一个订阅事件是可以触发多个回调的,所以我们取消订阅有两种模式,一种是取消某个回调,一种是取消整个事件订阅。

这里我们可传入两个值,一个是key一个是cb,如果没有传入cb则代表取消整个事件订阅。

取消整个事件订阅好办,直接将this.events内的对应key的属性delete即可。如果需要删除指定key的某个回调则需要把目标回调函数引用也传入off方法中,找到相应对象删除。

看到这里,大家可能会想,如果我传的是个匿名函数不是就没法取消了?恭喜你,答对了。所以我们在设置回调函数的时候尽量不要使用匿名函数。(如果我们确实需要取消应该咋办?在拓展中我们会展开讨论一下)

  • 事件发布 – emit

x

最后是事件发布,发布的重点在于参数的传递以及一次性订阅的取消。我们通过函数内置的arguments属性将需要传入触发事件的参数取出来,然后通过apply方法传入函数中。

对于不需要keep的订阅,我们则需要在handler触发后调用自身的off方法将其删除即可。

拓展

  • 发布/订阅模式和观察者模式,傻傻分不清

乍一看,两种模式十分相似,都有所谓的订阅与发布动作,但有一个很大的不同:调度方式。

发布/订阅模式有一个调度中心的概念,也就是我们这里所说的事件总线,所有的事件调度都是在这里面进行的;而观察者模式则是由被观察对象主动调度,没有事件总线的概念。相比之下发布/订阅模式更加解耦,发布、订阅者完全没有依赖。

  • 取消匿名函数回调

① 如果是一次性订阅则可以直接根据引用进行订阅取消。

② 如果不是一次性订阅,但是我们又想取消则可以参照setTimeout的做法,我们在订阅事件的时候随机生成一个token,并加入订阅对象中,最后作为on的返回值,暴露出来。取消订阅也是意义,就和我们clearTimeout一样,将token传入off方法中,达到取消的目的。