RxJS SwitchMap操作符未遍历Observable返回值问题求助
问题
我有两个Firebase列表:Raw Materials和Stock。Stock列表中的对象包含raw material key,我通过该键获取对应的原材料。在获取全部Stock列表后,尝试遍历每个对象关联对应的原材料,但Observable仅返回第一个对象,未遍历整个列表。
以下是我的代码:
rawMaterialsStocksRef: AngularFireList<any>; rawMaterialStockRef: AngularFireObject<any>; private dbPathStock = '/raw_material_stock'; constructor( private db: AngularFireDatabase, private rawMaterialService: RawMaterialsManagementService ) { this.rawMaterialsStocksRef = db.list(this.dbPathStock); } getRawMaterialStockList() { const rawData = this.rawMaterialsStocksRef.valueChanges().pipe( map(rawMaterialsStocks => rawMaterialsStocks.map(stock => ({ ...stock })) ), switchMap(stockArr => from(stockArr)), // gives the following // { "factoryKey": "34""quantity": "34", "rawMaterialKey": "-NDNPe47CDTbjmwGgW_3"} // { "factoryKey": "20", "quantity": "20", "rawMaterialKey": "-NDIjiVqKP-lLwJGwmic"} switchMap(stock => // this service i use to fetch each raw material based on its key this.rawMaterialService.getRawMaterial(stock.rawMaterialKey).valueChanges() .pipe( map(rawMaterial => { return { ...stock, ...rawMaterial } }) ) ), ); rawData.subscribe() }
返回结果如下:
{ "factoryKey": "20", "quantity": "20", "rawMaterialKey": "-NDIjiVqKP-lLwJGwmic", "code": "KLL2311", "name": "Material 03" }
可见尽管数组包含多个对象,但仅成功关联了一个。
解决方案
问题核心是switchMap的特性:当新的Observable发射值时,switchMap会立即取消之前的Observable订阅。你将数组转成逐个发射的Observable后,第二个stock对象发射时,第一个原材料的请求会被取消,最终仅保留最后一个请求的结果。
方案一:并行请求+合并结果(推荐,适合一次性获取数据)
使用forkJoin并行请求所有原材料数据,待全部请求完成后返回完整的关联结果数组:
getRawMaterialStockList() { const rawData = this.rawMaterialsStocksRef.valueChanges().pipe( switchMap(stockArr => forkJoin( stockArr.map(stock => this.rawMaterialService.getRawMaterial(stock.rawMaterialKey).valueChanges().pipe( map(rawMaterial => ({ ...stock, ...rawMaterial })) ) ) ) ) ); rawData.subscribe(result => { console.log(result); // 输出完整的关联后数组 }); }
方案二:逐个请求+收集结果(适合需要实时更新的场景)
如果需要持续监听Stock和Raw Materials的变化,用mergeMap替代switchMap(不会取消之前的请求),再通过scan逐步收集结果:
getRawMaterialStockList() { const rawData = this.rawMaterialsStocksRef.valueChanges().pipe( switchMap(stockArr => from(stockArr)), mergeMap(stock => this.rawMaterialService.getRawMaterial(stock.rawMaterialKey).valueChanges().pipe( map(rawMaterial => ({ ...stock, ...rawMaterial })) ) ), scan((acc, curr) => [...acc, curr], []) // 逐步收集结果,实时更新数组 ); rawData.subscribe(result => { console.log(result); // 每次有数据更新时输出最新数组 }); }
注意:toArray()需要等待所有Observable完成才会发射数组,若valueChanges()是持续监听的(不会完成),则不适用,此时优先用scan或combineLatest。
内容的提问来源于stack exchange,提问作者Sb Zakaria
相关产品推荐
相关产品推荐

