如何为Observable<Object[]>中的对象填充子对象数据?
嘿,你的当前实现肯定不对,我来给你拆解下问题,再给你正确的写法:
问题出在哪?
- 你在
map操作符里直接调用subscribe(),这会返回一个Subscription对象,而不是实际的SubObject数据——也就是说你的subObject属性最后存的是订阅实例,不是你要的子对象内容,完全不符合预期。 - 这种写法会触发N个独立的订阅(N是objects数组的长度),既没法统一管理这些订阅(容易忘取消导致内存泄漏),也没法在所有子对象都加载完成后再拿到完整的结果集。
正确的实现方式
应该用RxJS的switchMap结合forkJoin来处理,这样能并行发起所有子对象请求,等全部完成后再返回完整的对象数组:
import { forkJoin } from 'rxjs'; import { switchMap, take, map } from 'rxjs/operators'; // ... this.serviceA.getObjects().pipe( switchMap(objects => { // 给每个对象创建一个Observable,获取到subObject后合并成完整对象 const objectObservables = objects.map(obj => this.serviceB.getSubObject(obj.subObjectId).pipe( take(1), map(subObj => ({ ...obj, subObject: subObj })) ) ); // 并行等待所有请求完成,返回最终的完整对象数组 return forkJoin(objectObservables); }) ).subscribe(completeObjects => { // 这里拿到的就是每个都带正确subObject的数组啦 // 接下来可以把这个数组赋值给组件变量或者做其他处理 });
补充说明
switchMap用来切换Observable上下文:先拿到serviceA返回的对象数组,再把它转换成一个新的Observable(就是forkJoin那部分)。forkJoin会等待所有内部的Observable都完成(因为每个getSubObject都加了take(1),所以每个请求都会正常完成),然后把所有结果按顺序打包成数组返回。- 这样外层只需要一个订阅,取消的时候也只需要取消这一个订阅,避免了内存泄漏的问题。
如果你的场景需要顺序发起请求(比如必须等前一个子对象请求完成才发下一个),可以把forkJoin换成concat,不过一般并行请求效率更高,除非有特殊的业务限制。
内容的提问来源于stack exchange,提问作者Developer Marius Žilėnas
相关产品推荐
相关产品推荐

