如何无需等待所有Observable完成即可合并数组流 实现Angular销售数据即时展示
解决方案
核心原因是你现在直接merge两个数组流,页面会直接渲染流最新抛出的数组值,手动注入的单元素数组自然会覆盖之前服务端返回的完整列表。要实现增量追加+全量更新的逻辑,用scan操作符维护列表状态即可,不需要修改你现有InjectSale$.next()的调用逻辑。
修改后的代码如下:
// 需提前导入rxjs的map、scan操作符 import { map, scan } from 'rxjs'; // ... 原有其他代码保持不变 get LastSales() : Observable<Sale[]> { if (!this.displayLastSales$) { const rTimer$ = timer(0, DefaultRefresh); this.displayLastSales$ = rTimer$.pipe( switchMap(_ => this.getLastSales()), // 将服务端返回的全量数组映射为「全量替换状态」的更新函数 map(serverSales => (prevSales: Sale[]) => serverSales), shareReplay(this.CACHE_SIZE), takeUntil(this.refresherToggleSales$) ); } // 将手动注入的增量数组映射为「追加更新状态」的更新函数 const injectUpdate$ = this.InjectSale$.pipe( map(newSales => (prevSales: Sale[]) => [...prevSales, ...newSales]) ); // 合并两种更新函数流,用scan执行函数维护最终列表状态 return merge(this.displayLastSales$, injectUpdate$).pipe( // 初始状态可根据需求调整为空数组或者其他默认值 scan((currentSales: Sale[], updateFn) => updateFn(currentSales), []) ); }
逻辑说明
- 无需等待任意流完成,任意流有新值抛出时都会立刻计算最新的列表结果返回给模板渲染:
- 首次服务端返回数据时,会执行替换函数,把初始空数组替换为服务端返回的完整销售列表
- 手动调用
InjectSale$.next([newSale])时,会执行追加函数,把新录入的销售记录直接加到现有列表末尾,实现即时展示 - 下次定时拉取接口触发时,会用最新的服务端全量数据替换当前列表,保证本地数据和服务端最终一致
- 如果需要避免手动新增的记录和后续服务端返回的记录重复,可以把追加更新函数改成如下逻辑,按唯一标识去重即可:
map(newSales => (prevSales: Sale[]) => [ ...prevSales.filter(s => !newSales.find(n => n.id === s.id)), ...newSales ])
内容的提问来源于stack exchange,提问作者tsmr
相关产品推荐
相关产品推荐

