如何正确扁平化Observable数组?RxJS原生方案求解
问题分析与解决方案
你用concatAll/mergeAll出错的核心原因是:这俩操作符是用来扁平化高阶Observable(也就是Observable<Observable<T>>这种嵌套Observable)的,但forkJoin(ordersObservable)返回的是Observable<Order[][]>——它发射的是一个二维数组,不是嵌套Observable。
当你给这个二维数组用concatAll时,它会把数组当成可迭代对象,把每个子数组(Order[])单独发射出去,导致subscribe里的回调每次只收到一个子数组,自然会多次调用orderService.set。
正确的RxJS原生处理方案
针对你的场景(等所有Observable完成后,一次性得到合并后的完整Order[]),最直接高效的方式是在map里用数组原生的扁平化方法,这完全符合RxJS的使用规范:
const ordersObservable: Observable<Order[]>[] = []; // 填充ordersObservable... forkJoin(ordersObservable) .pipe( // 用数组的flat()方法直接扁平化二维数组 map(results => results.flat()) // 如果你需要兼容ES2019之前的环境,也可以用concat: // map(results => ([] as Order[]).concat(...results)) ) .subscribe((orders: Order[]) => { this.orderService.set(orders); // ...其他逻辑 });
额外说明:如果不需要等所有Observable完成
要是你想在每个Observable完成时就逐步合并结果(而不是等全部完成),可以用concat/merge合并Observable序列,再用scan收集结果,最后用last()拿到最终完整数组:
concat(...ordersObservable) .pipe( // 逐步合并每个Observable返回的Order[] scan((allOrders, currentOrders) => allOrders.concat(currentOrders), [] as Order[]), // 等所有Observable都完成后,发射最终的合并数组 last() ) .subscribe(orders => { this.orderService.set(orders); });
这种方式和forkJoin的区别是:如果某个Observable<Order[]>多次发射值(一般不会),scan会收集所有发射的数组,而forkJoin只会取每个Observable的最后一次发射值。
内容的提问来源于stack exchange,提问作者Willian Soares
相关产品推荐
相关产品推荐

