refCount 出现意外的 RxJS shareReplay 行为:true

问题描述 投票:0回答:1

当使用 shareReplay 与

refCount: true
时,我希望它在没有活动订阅时从源取消订阅,但它似乎挂在其他类型的引用上?我们在执行 http 请求时遇到了这种情况,该请求在发出后完成,但对于我使用的示例
of()
,它似乎做了同样的事情。

StackBlitz 示例

两个可观察量之间的唯一区别是其中一个以 take(1) 结尾。但在这两种情况下,他们的订阅者都completeunsubscribe,并且所有take操作符应该在N次发射之后完成,所以它看起来多余,但它确实改变了行为。

但是你可以看到,如果没有

take(1)
,badObservable 仍然相信它有一个引用,所以它不会从源取消订阅,也不会重新运行请求。

如果您将

take(1)
从共享可观察量中移开并将其与调用者配对,感觉会更奇怪,因为这样两个多播可观察量在定义时实际上是相同的,但您必须确保使用
 访问“好的”可观察量this.goodObservable.pipe(take(1)).subscribe({
以便共享可观察量正确地取消订阅/重新订阅原始源请求。但是,如果任何人出现并且突然执行
this.goodObservable.subscribe
操作,那么原始的共享可观察对象就会被所有未来的请求卡住,并且它永远不会从源取消订阅(在我们的例子中,永远不会再次发出 http 请求)。但重要的是,在这两种情况下
this.goodObservable.pipe(take(1)).subscribe
this.goodObservable.subscribe
订阅均已完成并声称已关闭/取消订阅!因此,从外部看,我看不到任何明显的差异,任何想知道“我是否需要 take(1) 或手动取消订阅”的人都会看到它已经完成/取消订阅,没有任何额外的内容,并且没有意识到仍然需要添加 take (1) 不要破坏底层的可观察值。

更新:

在 github 上深入研究后,我发现了一些与此相关的问题: https://github.com/ReactiveX/rxjs/issues/5587

https://github.com/ReactiveX/rxjs/issues/6760

https://github.com/ReactiveX/rxjs/issues/5894

看起来行为在某个时刻发生了变化,因此它不会重置导致的已完成的可观察值(并且显然仍然导致一些混乱)。在 refCount true 下获得预期的 shareReplay 功能的正确方法是仅使用 share:

    share({
      connector: () => new ReplaySubject(1),
      resetOnError: true,
      resetOnComplete: true,
      resetOnRefCountZero: true
    })

哪个有效。

我仍然不太明白的是,为什么 take(1) 会以某种方式绕过这个问题,即使对于在一次发射后完成的可观察量(如 http 请求)也是如此。在意识到源可观察对象在技术上也已完成之前,是否会以某种方式取消订阅并关闭它?

angular rxjs
1个回答
1
投票

您正在共享一个已完成的可观察量,因为

of()
将同步发出一次,并立即完成。 HTTP 请求也会做同样的事情,只是异步的。

当您共享一个已完成的可观察值时,其结果将永远保存在底层 Replay 中,如文档中所述:

成功完成的源将永远缓存在 shareReplayed 可观察中,但错误的源可以重试。

如果您修改示例以使用未完成的可观察量,您将看到结果实际上已共享并且行为符合预期:


https://stackblitz.com/edit/stackblitz-starters-s5ecqt?file=src%2Fmain.ts

© www.soinside.com 2019 - 2024. All rights reserved.