# 如何解决页面中使用emitter.emit执行卡顿问题

#### 问题现象

在页面中存在一个按钮组件，其点击事件触发调用emitter的emit方法以分发事件，随后跳转至新页面并通过emitter.on()方法监听该事件完成页面交互。经多次重复执行该流程后，发现事件监听与响应存在延迟现象。

#### 背景知识

emitter是一种作用在进程内的事件处理机制，为应用程序提供订阅事件、发布事件、取消事件订阅的能力。emitter.emit发送指定事件，emitter.on持续订阅指定的事件，并在接收到该事件时，执行对应的回调处理函数。emitter.off取消事件ID为eventId的所有订阅。

#### 问题定位

1.  在页面上多次重复执行分发事件并监听事件的步骤。
2.  查阅日志发现目标页的监听会重复监听：
    
    ```
    emitter/JSAPP  com.examp...nemitter  I     MyPageOne aboutToAppear
    emitter/JSAPP  com.examp...nemitter  I     receive
    emitter/JSAPP  com.examp...nemitter  I     MyPageOne aboutToAppear
    emitter/JSAPP  com.examp...nemitter  I     receive
    emitter/JSAPP  com.examp...nemitter  I     receive
    emitter/JSAPP  com.examp...nemitter  I     MyPageOne aboutToAppear
    emitter/JSAPP  com.examp...nemitter  I     receive
    emitter/JSAPP  com.examp...nemitter  I     receive
    emitter/JSAPP  com.examp...nemitter  I     receive
    ```
    
3.  通过设置页面销毁时移除监听或监听单次事件，查看日志发现监听触发多次监听的问题已不存在。

#### 分析结论

事件监听延迟的核心原因是重复订阅事件或未及时移除监听器，导致同一事件触发时需执行过多冗余的回调函数。具体原因为：

*   监听器未清理：
    
    页面跳转时未在组件卸载生命周期中调用emitter.off()，导致旧监听器残留。多次操作后，相同事件会触发所有历史监听器，回调堆积导致延迟。
    
*   单次事件误用多次监听：
    
    若事件为一次性操作（如页面初始化数据加载），但监听器未设置为单次触发emitter.once()，则每次跳转都会新增监听器，形成冗余。
    

#### 修改建议

针对一次性操作，使用一次性监听emitter.once()代替emitter.on()，并在页面销毁时执行emitter.off()。

#### 常见FAQ

Q：emitter.off取消订阅某个事件后，是不是所有订阅该事件的地方都不会再收到该事件的消息？

A：是的，emitter.off取消订阅某个事件后，所有订阅这个事件的地方都不会再收到这个事件的消息。

Q：eventId一样时，emitter多次调用on是否能注册多个回调？

A：针对同一个eventId多次注册订阅时，若关联的回调对象为同一个，则只会生效第一次注册的回调对象，若关联的回调对象不同，则多个回调对象均生效，由on的顺序决定回调顺序，同时off注销时，eventId与回调对象需配对，否则回调注销失败。

#### 总结

*   事件监听需与组件生命周期强绑定：
    
    组件的订阅行为必须与清理函数严格关联，确保“订阅即绑定，卸载即清理”，避免监听器残留。
    
*   一次性事件优先使用once模式：
    
    对于仅需触发一次的场景（如页面初始化），使用emitter.once()并配合手动清理，双重保障避免冗余。
    
*   性能问题需预防性编码：
    
    在事件设计初期就考虑监听器的生命周期管理，而非问题出现后补救。例如：
    
    *   默认在组件销毁时清理监听。
    *   为每个监听器添加日志标识，便于追踪来源。