Subject 的核心概念
Subject 是 RxJS 中一种特殊的 Observable,它既是 Observable 又是 Observer。这意味着它可以:
- 被多个观察者订阅
- 主动推送新值给所有订阅者
- 实现多播(multicast)功能
Subject 类型
1. Subject
基础 Subject,每次有新订阅者时,不会回放之前的值
javascriptconst subject = new Subject(); subject.next(1); subject.next(2); const subscription1 = subject.subscribe(value => console.log('订阅者1:', value)); // 订阅者1: 3 // 订阅者1: 4 subject.next(3); subject.next(4); const subscription2 = subject.subscribe(value => console.log('订阅者2:', value)); // 订阅者2: 5 // 订阅者2: 6 subject.next(5); subject.next(6);
2. BehaviorSubject
BehaviorSubject 会记住最新的值,新订阅者会立即接收到当前值
javascriptconst behaviorSubject = new BehaviorSubject('初始值'); behaviorSubject.subscribe(value => console.log('订阅者1:', value)); // 订阅者1: 初始值 behaviorSubject.next('值1'); // 订阅者1: 值1 behaviorSubject.subscribe(value => console.log('订阅者2:', value)); // 订阅者2: 值1 - 立即收到最新值 behaviorSubject.next('值2'); // 订阅者1: 值2 // 订阅者2: 值2
3. ReplaySubject
ReplaySubject 可以回放指定数量的历史值
javascriptconst replaySubject = new ReplaySubject(2); // 回放最后2个值 replaySubject.next('值1'); replaySubject.next('值2'); replaySubject.next('值3'); replaySubject.subscribe(value => console.log('订阅者1:', value)); // 订阅者1: 值2 // 订阅者1: 值3 replaySubject.next('值4'); // 订阅者1: 值4 replaySubject.subscribe(value => console.log('订阅者2:', value)); // 订阅者2: 值3 // 订阅者2: 值4
4. AsyncSubject
AsyncSubject 只在完成时发出最后一个值
javascriptconst asyncSubject = new AsyncSubject(); asyncSubject.subscribe(value => console.log('订阅者1:', value)); asyncSubject.next('值1'); asyncSubject.next('值2'); asyncSubject.next('值3'); // 此时还没有输出 asyncSubject.complete(); // 订阅者1: 值3 - 只发出最后一个值 asyncSubject.subscribe(value => console.log('订阅者2:', value)); // 订阅者2: 值3 - 新订阅者也能收到最后一个值
实际应用场景
Subject 使用场景
- 事件总线
- 状态管理
- 多个组件共享数据流
BehaviorSubject 使用场景
- 存储当前状态
- 表单状态管理
- 用户信息管理
ReplaySubject 使用场景
- 缓存历史数据
- 重播操作日志
- 错误重试机制
AsyncSubject 使用场景
- HTTP 请求缓存
- 只需要最终结果的计算
- 异步操作的最后值
与普通 Observable 的区别
javascript// 普通 Observable - 单播 const observable = new Observable(subscriber => { subscriber.next(1); subscriber.next(2); }); observable.subscribe(v => console.log('观察者1:', v)); observable.subscribe(v => console.log('观察者2:', v)); // 每个订阅者独立执行 // Subject - 多播 const subject = new Subject(); const source = new Observable(subscriber => { subscriber.next(1); subscriber.next(2); }); source.subscribe(subject); subject.subscribe(v => console.log('订阅者1:', v)); subject.subscribe(v => console.log('订阅者2:', v)); // 所有订阅者共享同一个数据流
性能考虑
Subject 在多播场景下可以提高性能,避免重复执行相同的异步操作。但需要注意内存泄漏问题,及时取消订阅。