wencaizhang
Open for collabs!

mitt 上手教程

Published onAugust 03, 2025
-Views
5Minutes Read
是一个非常轻量级的事件发射器(Event Emitter),它的核心思想是提供一个简单的发布/订阅(Pub/Sub)模式,让你可以轻松地在应用程序的不同部分之间进行通信,而无需它们直接相互依赖。

一、基础用法:创建、监听与触发

的 API 非常直观,主要围绕以下三个核心方法:

1. 创建事件总线 (Emitter)

实际上是一个工厂函数,它返回一个
实例。

2. 监听事件 (on)

使用
方法来订阅一个事件。
它接收两个参数:事件名(字符串)和回调函数。当事件被触发时,回调函数就会被执行。
这一点类似 jQuery 的事件监听,不过事件名是可以自由定义的。

3. 触发事件 (emit)

使用
方法来发布或触发一个事件。它接收两个参数:事件名(字符串)和可选的事件数据。事件数据可以是你想要的任何类型,比如对象、字符串或数字。
那么在上一节的「监听 'foo' 事件」代码中就会打印:

4. 移除监听器 (off)

当某个组件不再需要监听事件时,你可以使用
方法来移除监听器。
也需要传入事件名回调函数
以 Vue3 代码为例, 在组件卸载前通常需要移除监听器:
传入的回调函数必须是监听时使用的同一个函数引用,否则无法移除。这一点和 JS 的 addEventListener 类似。

二、进阶用法:更强大的功能与实践模式

1. 监听所有事件

监听所有事件
支持使用
作为事件名来监听所有被触发的事件。你的回调函数会接收到两个参数:

2. 移除所有监听器

当你只传入第一个参数(事件名)时,所有与该事件名关联的监听器都会被移除。
方法是一个重载函数,它的行为取决于你传入的参数数量:
  • :移除该
    事件的所有监听器。
  • emitter.off(type, handler)
    type
    handler` 监听器。
你还可以使用
方法,一次性清除所有事件的所有监听器。
实际上是一个
类型,因此可以使用
以及其他
实例的方法: Map - JavaScript | MDN

3. 命名空间: 通过事件命名规范实现轻量级隔离

在只使用一个
实例时,你可以通过为事件名添加前缀来创建“命名空间”,从而避免事件冲突和增强可读性。
命名方式建议使用冒号或斜杠分隔符,如
,核心思想是:
+
例如:
使用命名空间后,你可以利用字符串操作来做一些灵活的批量处理。 例如,如果你想监听所有与用户相关的事件,你只需要在监听器中判断事件名是否以
开头即可。
这种模式让你在同一个
实例上,也能实现类似分组的效果,大大提升了事件处理的灵活性。
总的来说,命名空间的方式有三个好处:
  1. 避免冲突,增强代码健壮性
  2. 提高可读性,一眼看懂事件来源
  3. 实现批量操作和灵活筛选
但缺点也很明显,那就是命名空间是一种人为的约束,依赖于团队的纪律性。

4. 创建多个独立实例:实现物理隔离

在大型或复杂的应用中,为不同的功能模块创建独立的
实例是更好的选择。这是一种代码层面的强制隔离,更安全、更健壮。
直接为不同模块创建单独的
实例,可以让你更好地控制事件的范围和范围内的通信。
然后在不同模块中,只需要导入对应的
实例,就可以进行事件的发布和订阅。
不同的
实例之间是完全隔离的,互不影响。

三、记得在适当时机接触监听

为什么需要解除监听?

如果不解除监听,可能会导致以下两个主要问题:

1. 内存泄漏 (Memory Leak)

当你为一个事件添加了监听器后,这个监听器就会被事件总线(
实例)所“持有”。如果你的组件被销毁(例如,用户从一个页面跳转到另一个页面),但你没有移除这个监听器,事件总线仍然会保留对该组件回调函数的引用。
这意味着即使组件的 DOM 元素和数据已经被垃圾回收器清除,这个回调函数及其闭包中引用的所有数据(包括组件实例本身)依然无法被回收。随着用户在应用中不断切换页面,越来越多的废弃监听器会堆积在内存中,最终导致应用程序的性能下降,甚至崩溃。

2. 意料之外的行为和 bug

假设你有一个组件 A,它监听了
事件。当用户登录时,组件 A 会执行某个操作。
想象下面的场景:
  1. 你进入了组件 A 所在的页面。
  2. 你离开了这个页面,组件 A 被销毁了。
  3. 你又重新进入了组件 A 所在的页面,一个新的组件 A 实例被创建。
  4. 现在,事件总线上实际上有两个
    的监听器:一个来自旧的、已销毁的组件,另一个来自新的组件。
  5. 当用户登录时,这个事件会被触发两次,导致你的逻辑被重复执行,从而产生难以追踪的 bug。

示例说明

下面是关键代码:
如果是 react 项目,可以在 useEffect 的回调函数中清除监听:

四、结语

是一个非常轻量级的事件发射器,它提供了一种简单、灵活的发布/订阅模式,可以帮助你在应用程序的不同部分之间进行通信。
它的 API 非常直观,使用起来也很方便,但它也有一些局限性,比如命名空间的约束、批量操作的不便,而且大量使用
会增加代码的复杂度,增加维护难度,并且难以跟踪和管理,从长期来看维护起来会让人头疼。
不过,如果你有更复杂的需求,比如需要实现更高级的功能,或者需要更灵活的架构,
也是一个不错的选择。
Tags:
#Mitt