You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 03:10:44