有人能告诉我我的 RXJS 代码是如何工作的吗?

时间:2021-02-19 10:57:07

标签: angular typescript rxjs

 this.httpService.get('/user/appUser').pipe(
  concatMap(users => users),
  concatMap(user =>
    forkJoin({
      billingAddr: this.httpService
        .get('/user/appUserAddr', new HttpParams()
          .set('where', JSON.stringify([{ pk_addr_name: user['fk_billing_addr_name'] }]))
        ),
      shippingAddr: this.httpService
        .get('/user/appUserAddr', new HttpParams()
          .set('where', JSON.stringify([{ pk_addr_name: user['fk_shipping_addr_name'] }]))
        )
    }).pipe(map(addr => {
      user['billingAddr'] = addr.billingAddr;
      user['shippingAddr'] = addr.shippingAddr;
      return user;
    }))
  ),
  tap(res => console.log(res)),
  toArray()
);

第一个 HTTP 请求(get '/user/appUser') 将返回一个这样的数组:

[  
{user_name:'test1',fk_billing_addr_name:'addr1-1',fk_shipping_addr_name:'addr1-2'},  
{user_name:'test2',fk_billing_addr_name:'addr2-1',fk_shipping_addr_name:'addr2-2'}
]

然后我将获得单独的 billingAddr 和 shippingAddr 并将其添加回用户对象本身,这是第二个 concatMap 部分。

最终输出将如下所示:

[  
{user_name:'test1',fk_billing_addr_name:'addr1-1',fk_shipping_addr_name:'addr1-2',billingAddr:[...],shippingAddr:[...]},  
{user_name:'test2',fk_billing_addr_name:'addr2-1',fk_shipping_addr_name:'addr2-2',billingAddr:[...],shippingAddr:[...]}
]  

实际上我的代码是有效的,但奇怪的部分是第一个 concatMap(users=>users)。
如果我不把它放在那里,用户数组就不能一个一个地发送给下一个操作符。 我可以只用一个 concatMap 来简化它吗? 还有我可以简化的任何其他部分吗?

1 个答案:

答案 0 :(得分:2)

这当然是一个有趣的问题。这是怎么回事

  1. 获取初始数组。
  2. First concatMap 按顺序发出数组的每个元素。类似于from(array)
  3. 使用第二个 forkJoin 映射到 concatMap 的 observable。
  4. 通过使用 forkJoin 获取和分配两个新属性来调整每个元素。
  5. 使用 toArray() 运算符将末尾的所有元素/发射再次组合为一个数组并发射。

我没有发现它有什么问题,除非你在等待当前用户在开始下一个之前获取它的数据。

但是,如果您希望完全并行化提取,则可以使用两个 forkJoin。内部 forkJoin 类似于现有用法,外部 forkJoin 替换 concatMaptoArray。此处的 switchMap 可以替换为任何其他映射运算符。由于 Angular HTTP 请求在第一次发出后完成,因此使用的映射运算符类型没有任何影响。

注意:这是未经测试的代码。请报告任何意外后果。

this.httpService.get('/user/appUser').pipe(
  switchMap(users => 
    forkJoin(users.map(user => 
      forkJoin({
        billingAddr: this.httpService
          .get('/user/appUserAddr', new HttpParams()
            .set('where', JSON.stringify([{ pk_addr_name: user['fk_billing_addr_name'] }]))
          ),
        shippingAddr: this.httpService
          .get('/user/appUserAddr', new HttpParams()
            .set('where', JSON.stringify([{ pk_addr_name: user['fk_shipping_addr_name'] }]))
          )
      }).pipe(
        map(addr => ({
          ...user,
          billingAddr: addr.billingAddr,
          shippingAddr: addr.shippingAddr
        }))
      )
    ))
  )
)

通过将 concatMap 替换为 mergeMaps

可以在您的代码中获得相同的结果