如何从单个Observable<Person[]>生成两个修改后的Observable<Person[]>实例
问题原因分析
tap是副作用操作符,本身不会对流发射的数据做转换,仅适合执行日志、外部调用等逻辑,不符合数据转换的使用场景,多订阅时的时序问题会导致你遇到的取到原始数据的问题。- 之前用
map出错是因为直接修改了原始Person对象的属性:JS 中对象为引用类型,原始流发射的数组内的对象是多订阅共享的,第一个流修改原对象后,第二个流拿到的就是已经被修改的数据,自然结果不符合预期。
实现方案
核心逻辑有两点:
- 原始流使用
share操作符做多播,避免多次订阅触发重复的上游逻辑 - 转换数据时返回新的对象拷贝,不修改原始数据,两个流的转换逻辑互不影响
完整代码示例
import { Observable, of } from 'rxjs'; import { map, share } from 'rxjs/operators'; // 你贴的接口名为ToolfaceData,和前文的Person描述不一致,统一修正为Person即可 export interface Person { age: number; name: string; } // 原始源流,添加share做多播 const source$: Observable<Person[]> = of([ { age: 2, name: 'Anne' }, { age: 5, name: 'Bob' } ]).pipe(share()); // 第一个流:age统一加2,每次返回新对象,不修改原数据 const ageAdd2$ = source$.pipe( map(personList => personList.map(p => ({ ...p, // 浅拷贝原有属性 age: p.age + 2 })) ) ); // 第二个流:age统一减2,同样返回新对象 const ageMinus2$ = source$.pipe( map(personList => personList.map(p => ({ ...p, age: p.age - 2 })) ) );
效果验证
分别订阅两个流即可得到预期结果:
ageAdd2$.subscribe(console.log); // 输出:[{age:4, name:'Anne'}, {age:7, name:'Bob'}] ageMinus2$.subscribe(console.log); // 输出:[{age:0, name:'Anne'}, {age:3, name:'Bob'}]
注:如果你的Person对象包含深层嵌套属性,把浅拷贝替换为深拷贝逻辑即可,当前单层结构用扩展运算符
...足够。
内容的提问来源于stack exchange,提问作者g1wonwon
相关产品推荐
相关产品推荐

