为什么在groupBy运算符之后未调用订阅?

时间:2019-10-31 18:24:53

标签: javascript angular rxjs

为什么第二个示例的订阅方法未调用?

两个示例中管道中的所有日志均按预期方式工作。

工作示例:(但使用硬编码的数据和创建者):


of([
  {tableName: 'table1', firstName: 'name1', lastName: 'lastName1'},
  {tableName: 'table1', firstName: 'name2', lastName: 'lastName2'},
  {tableName: 'table2', firstName: 'name3', lastName: 'lastName3'},
  {tableName: 'table2', firstName: 'name4', lastName: 'lastName4'}
]).pipe(
  tap(data => console.log('amount of records', data.length)),
  mergeMap((searchResult) => searchResult),
  groupBy(b => b.tableName),
  mergeMap(group => {
    console.log('groupKey', group.key);
    return group.pipe(toArray());
  })
).subscribe(val => console.log(val));

问题代码:(直接使用来自ngrx商店的数据,并且数据结构与上面的代码工作示例相同)


this.store.pipe(
  select(selectSearchResult),
  tap(data => console.log('amount of records', data.length)),
  mergeMap((searchResult) => searchResult),
  groupBy(b => b.tableName),
  mergeMap(group => {
    console.log('groupKey', group.key);
    return group.pipe(toArray());
  })
).subscribe(val => console.log(val)); // <- this is not called!?

我希望每个组都调用subscription方法,因为 上面带有硬编码数据的示例。但是具有讽刺意味的是没有订阅方法吗?!

enter image description here

商店交付的商品不在阵列中的示例:

2 个答案:

答案 0 :(得分:1)

我认为问题出在这里

商店是可观察到的长寿。这意味着:它本身不会完成

toArray收集有关其源流的所有通知,直到该流完成,然后仅发送一条包含项数组的通知。

否则,如何知道何时准备将数组发送给下一个运算符?总是会有另一个通知,可能会使数组更大。

请注意,由GroupedObservable产生的groupBy在完成其来源之前是不会完成的。由于源store不会完成,因此toArray将永远不会收到complete消息。

解决方案是:重构代码,以便使用from获得可观察的结果。 from将数组作为参数,为每个数组项发送一个通知,然后发送完整通知,向toArray表示它可以发送通知。这应该起作用:

mergeMap((searchResult) => 
  from(searchResult).pipe(
    groupBy(b => b.tableName),
    mergeMap(group => {
      console.log('groupKey', group.key);
      return group.pipe(toArray());
  })
))

来源:RxJS Code请看GroupedObservable何时完成。

答案 1 :(得分:0)

它认为您将groupBy作为在数组而不是流上使用的函数感到困惑,RxJs函数适用于流,而不适用于流所发出的值。

groupBy不对流发出的数组进行分组,而是对流进行分组。就像每次可观察对象发出一个对象一样,它被添加到组中。如果要对存储中的数组进行分组,则需要与数组一起使用的groupBy函数。

这是我编写的带数组https://stackblitz.com/edit/typescript-ezydzv

的groupBy函数的示例

map是RxJs函数,用于操纵流发出的对象,并且可以在map中将groupBy应用于数组。

this.store.pipe(
  select(selectSearchResult),
  tap(data => console.log('amount of records', data.length)),
  map(data => groupBy(data, { keys: ['tableName'] }))
).subscribe(val => console.log(val));