🧠 一、Emitter 是什么?
Emitter
是 HarmonyOS 提供的一个轻量级事件通信机制 ,用于实现进程内、线程间的异步事件通知与订阅 。它类似于 Node.js 中的 EventEmitter
,但为 ArkTS 框架和线程模型进行了专门优化,尤其适合组件解耦、Worker 通信、UI 与后台同步等场景。
⚙️ 二、Emitter 的核心设计原理
1. 事件队列机制
Emitter
内部维护了一个 事件队列 ,所有通过 emit
发布的事件都会进入该队列。
- 队列以 FIFO(先进先出) 的方式异步串行执行事件回调。
- 通过设置事件优先级(如 LOW / IMMEDIATE)影响事件在队列中的调度顺序。
2. 异步串行调度
- 所有订阅的回调函数在事件被触发后会逐个执行。
- 如果某个回调耗时过长,可能会阻塞后续事件执行,所以建议回调中避免同步阻塞逻辑。
3. 线程安全设计
- Emitter 本质上是一种线程间消息传递机制,但其使用方式简洁,无需复杂的线程同步操作。
- 适用于主线程(UI线程)与 Worker线程(如后台处理)之间的数据通信。
🛠️ 三、Emitter 的核心接口详解
方法名 |
描述 |
使用示例 |
on(event, callback) |
注册事件监听,持续有效,需手动取消 |
emitter.on({ eventId: 1 }, cb) |
once(event, callback) |
注册事件监听,只触发一次后自动移除 |
emitter.once({ eventId: 1 }, cb) |
off(eventId, callback) |
注销指定事件和回调函数的订阅 |
emitter.off(1, cb) |
emit(event, data) |
发布事件并传递数据 |
emitter.emit({ eventId: 1 }, { data: xxx }) |
✅ 接口参数详解:
event: { eventId: string | number, priority?: EventPriority }
eventId
: 自定义事件标识(可使用字符串或数字)
priority
: 事件优先级(可选)
data: { data: any }
🧵 四、线程与进程模型下的使用
场景:主线程与 Worker线程 通信
1. Worker 线程发布事件
ts
复制代码
// worker线程
emitter.emit({ eventId: 'background_done' }, { data: '处理完成' });
2. 主线程监听事件
ts
复制代码
emitter.on({ eventId: 'background_done' }, (eventData) => {
this.result = eventData.data;
this.updateUI(); // 注意线程安全性
});
💡 线程间通信不需要共享变量或 postMessage,Emitter 自动桥接数据流
📦 五、状态管理与 UI 刷新注意事项
常见问题:UI 未响应事件更新?
原因:
- 回调中更新的数据变量 未被响应式装饰器(如 @ObservedV2、@State、@Provide)修饰。
- 回调中使用了早绑定的箭头函数,未捕获响应式代理对象。
正确做法:
ts
复制代码
@ObservedV2
class ViewModel {
@Trace count: number = 0;
increment() {
this.count++;
}
}
// 生命周期绑定回调
aboutToAppear() {
emitter.on({ eventId: 'count_update' }, () => {
this.viewModel.increment();
});
}
🧪 六、常见使用场景
场景 |
描述 |
✅ 跨线程通信 |
主线程与 Worker 通信,替代 postMessage 等复杂机制 |
✅ 模块解耦 |
非父子组件间的数据广播,如登录成功后全局通知 |
✅ 动态事件订阅 |
某个业务模块需要在运行时动态监听任务完成状态 |
✅ UI控制逻辑 |
后台服务状态变化驱动界面展示或提示 |
📊 七、与 EventHub 的差异总结
特性 |
Emitter |
EventHub |
使用场景 |
跨线程通信,模块解耦 |
组件内通信,UI层事件传递 |
线程支持 |
支持主线程 + Worker线程 |
仅支持 UI线程 |
事件调度 |
异步、优先级队列 |
同步、立即执行 |
生命周期 |
手动取消订阅 |
生命周期自动释放(Stage组件) |
响应式集成 |
需要配合状态装饰器 |
更紧密集成 UI 生命周期 |
🧹 八、资源管理与内存泄漏风险
✔️ 正确做法
- 页面或模块销毁时务必手动调用
off
方法取消订阅
- 推荐使用
once
替代短期监听,避免忘记取消
示例:
ts
复制代码
private onCallback = (data) => { ... };
aboutToAppear() {
emitter.on({ eventId: 'task' }, this.onCallback);
}
aboutToDisappear() {
emitter.off('task', this.onCallback);
}
🔒 九、最佳实践建议
建议 |
描述 |
✅ 封装事件工具类 |
统一事件管理,封装 on/off/emit 逻辑,避免重复代码 |
✅ 使用枚举管理事件ID |
防止硬编码,提升可读性 |
✅ 避免多个回调监听同一个事件 |
可能造成重复响应,应通过中间层转发 |
✅ 日志跟踪事件流程 |
emit / on 处记录日志便于调试 |
📁 十、封装工具类示例(建议应用)
ts
复制代码
export enum AppEvent {
LOGIN_SUCCESS = 'login_success',
DATA_READY = 'data_ready',
}
export class EmitterUtil {
private static registry = new Map<string, Function[]>();
static on(eventId: string, cb: Function) {
emitter.on({ eventId }, cb);
const list = this.registry.get(eventId) || [];
list.push(cb);
this.registry.set(eventId, list);
}
static emit(eventId: string, data: any) {
emitter.emit({ eventId }, { data });
}
static off(eventId: string) {
const list = this.registry.get(eventId) || [];
list.forEach(cb => emitter.off(eventId, cb));
this.registry.delete(eventId);
}
}
✅ 总结一句话
Emitter 是 HarmonyOS 架构中适用于线程间、模块间通信的高效、非侵入式事件调度器。通过合理封装与状态集成,可实现高内聚、低耦合的通信机制。