Typescript RxJS:groupBy与计时器一起使用时不发出值

Typescript RxJS:groupBy与计时器一起使用时不发出值,typescript,rxjs,Typescript,Rxjs,新加入RxJS(^6.5.5),我遇到了groupBy操作符的问题。下面是一个简单的例子 我有一个函数retrieveFiles(),它返回一个字符串数组 function async retrieveFiles(): Promise<string[]> { return ['file1.txt', 'file2.txt', 'file3.txt', 'directory1', 'directory2']; } 这将向订阅服务器发送两个值 [ 'file1.txt', 'fil

新加入
RxJS
^6.5.5
),我遇到了
groupBy
操作符的问题。下面是一个简单的例子

我有一个函数
retrieveFiles()
,它返回一个字符串数组

function async retrieveFiles(): Promise<string[]> {
  return ['file1.txt', 'file2.txt', 'file3.txt', 'directory1', 'directory2'];
}
这将向订阅服务器发送两个值

[ 'file1.txt', 'file2.txt', 'file3.txt' ]
[ 'directory1', 'directory2' ]
现在,让我们介绍
计时器
并稍微更改代码。我们现在基本上是在投票

timer(0, 1000)
  .pipe(
    concatMap(() => this.retrieveFiles()),
    mergeMap(value => value),
    groupBy(
      (name: string) => name.substr(0, 4),
      (name: string) => name,
    ),
    mergeMap(group$ => group$.pipe(toArray())), 
  )
  .subscribe(console.log);

这将不再发出任何值。这两者之间的区别是什么?

在第二种情况下,区别在于
计时器
从不完成,而
完成,而
toArray只在其源代码完成时发出,但是源没有完成,因为来自
groupBy
的分组可观测值预计未来的排放量,因为
timer
是源,所以它永远不会完成分组可观测值

如果您希望为每次轮询生成新组,则需要进行较小的重组,以使
retrieveFiles
成为其源

timer(0, 1000)
  .pipe(
    // recommend use switchMap so a hanging request doesn't clog your stream
    switchMap(() => from(retrieveFiles()).pipe( // need from to make it pipeable
      mergeMap(value => value),
      groupBy(
        (name: string) => name.substr(0, 4),
        (name: string) => name,
      ),
      mergeMap(group$ => group$.pipe(toArray())), 
    )),
  )
  .subscribe(console.log);

不过,关于这是否值得,这里有一个有效的讨论。您可以通过一个简单的
map
操作符实现这一目标,该操作符中包含一个同步数组分组函数,而不是所有的来回流转换。如果您只是在探索库,这很酷,但实际上,我不建议您这样做
groupBy
用例并不常见,但应保留用于处理实际的值流,您希望将其分组为单独的可观察流

此代码中存在错误
concatMap(v=>v),
无效,如果(retrieveFiles())
类型为
可观察
是否应为
可观察
mergeMap(value=>value),
部分在这两种情况下都是无效的。为什么
retrieveFiles
需要返回一个可观察的值?是的,这就是为什么(retrieveFiles())
类型将是
可观察的
我错了,我忘了rxjs可以让你在新版本6.5.5中更快、更宽松地使用数组和承诺,我将在问题中提到这一点。Thank.开始尝试使用RxJS,因为它很容易设置轮询,并且在找到新文件时发出新值。我决定看看是否能把他们也分组。但是,我可以使用
Array.reduce
收集文件并处理RxJS之外的分组。我没有观察单独的可观察流的用例。是的,四处探索是很有趣的,但如果这是你的目标,在
映射
操作符中使用数组reduce似乎是一种方法。强烈建议移动到
switchMap
,但如果您真的使用它进行轮询,因为
concatMap
将等待挂起请求并可能产生背压,而
switchMap
将取消并继续。未意识到
toArray
仅在源代码完成时发出。在本地实施修复,效果很好。感谢您指出我的错误和
swithMap
建议。
timer(0, 1000)
  .pipe(
    // recommend use switchMap so a hanging request doesn't clog your stream
    switchMap(() => from(retrieveFiles()).pipe( // need from to make it pipeable
      mergeMap(value => value),
      groupBy(
        (name: string) => name.substr(0, 4),
        (name: string) => name,
      ),
      mergeMap(group$ => group$.pipe(toArray())), 
    )),
  )
  .subscribe(console.log);