用 JavaScript 构建事件系统
文章目录
简介
在组件化开发越来越流行的今天,事件系统演者着非常重要的角色,它经常作为组件间通讯的桥梁。 本文将讨论如何用 JavaScript 实现一个简单的事件系统。
基本结构
我们先回想一下使用事件系统的方式。
通常,我们要先通过 on
/ listen
方法注册为一个事件注册一个回调函数。
然后调用 emit
/ fire
来触发一个事件,该事件对应的回调函数就会一一触发。
这样就是我们平常使用的事件系统的工作方式。
事件系统本质上是一个键值对的合集,一个事件名对应多个函数。
在 JavaScript 中,我们很容易用一个 Object
来模拟这种行为。如:
|
|
上面的结构表示有三个事件:ADD_ENTITY
, REMOVE_ENTITY
, UPDATE_ENTITY
,它们对应了一些回调函数。
当 ADD_ENTITY
触发的时候,fn1
, fn2
, fn3
都会依次调用,如此类推。
on & off & emit
接下来我们将利用上述的结构来实现事件系统。其中最基本的三个操作是:
on
监听事件off
移除事件emit
触发事件
按照上述的结构,我们很容易可以写出如下的代码:
|
|
上面的代码非常简单,on
和 off
只是在操作 Object
,为其添加、更新或删除一些键值对。
而 emit
方法只是根据给定的事件名来调用它相关的回调函数。
这样,我们就实现了一个简单的事件系统:
|
|
once
有些时候,我们需要指定某些回调函数只触发一次。 如:当页面加载完成后,执行初始化操作,这个操作就只会执行一次,之后再执行就不会生效。 上面的事件系统无法实现这种需求,因为每次触发事件,所有绑定的回调事件都会执行,不存在只执行一次的情况。
其实,我们只需要在执行回调函数后把该函数从列表中移除,就可以实现这种需求。 在这之前,我们先想想应该如何存储这些需要移除的函数。 存储方式大概有两种,一种是和不需要移除的函数保存在一起,即:
|
|
这种方式在用 emit
触发事件的时候,需要根据 once
属性来判断是否需要移除该回调函数。
另外,这种方式还有一个好处,它能保证回调函数的调用顺序。
另一种方式则是分开存储,通过引入一个新的变量来区分一次生效和多次生效的回调函数,如:
|
|
这种方式把两种函数隔离开,在移除回调函数的时候变得非常方便,直接移除整个 key 即可。
无论我们选择哪种存储方式,对 once
的实现影响都不大,因为只需要对 on
方法做一点修改就可以了。
同样,对于删除函数的操作,第一种方式只需要找出 once
为 true
的列表索引,然后根据索引来移除即可,而第二种方式直接删除 key 就可以了。
实现起来都比较简单,因此就不给出示例代码了。
参考资料
文章作者 scarletsky
上次更新 2019-04-30 (95a170d)