首页 > 解决方案 > 每次订阅都需要退订吗

问题描述

我正在尝试确定如何处理以下代码

let sub = myObservable.subscribe(
    v => doThing(v),
    e => handle(e),
    () => sub.unsubscribe(),
)

问题是 1. 此代码不正确,因为 myObservable 同步完成,完成时会抛出 NPE。2. 尽管我怀疑这里的取消订阅呼叫是一个好习惯。我不禁觉得这可能没有必要,因为我在其他任何地方都没有看到它完成。

我已经阅读了这篇文章https://blog.angularindepth.com/why-you-have-to-unsubscribe-from-observable-92502d5639d0但它实际上让我比开始时更加困惑。

如果我做

let subA = myObservable.pipe(take(1)).subscribe()
let subB = myObservable.pipe(takeUntil(foo)).subscribe()

我不再需要取消订阅 subA 和 subB 了吗?

这里的 subC 怎么样?

let subC = myObservable.pipe(finalize(() => cleanupOtherResources())).subscribe()

或者我是否必须将所有订阅添加到每个调用subscribe()任何类的列表中BehaviorSubject并立即取消订阅?

谢谢!

标签: rxjs

解决方案


退订始终是最佳做法。如果您知道您的类的 clean up 方法实际上是在可观察到的 cleanup 上发出的,那么 takeUntil 就可以使用。take 并不总是保证 observable 已经发出。在某些情况下,您知道 observable 肯定会至少发出一次,但仍有可能造成泄漏。

假设 observable 将完成的问题是您不知道服务的内部是否返回 observable 更改。如果您假设 observable 是一个 http 请求并在请求结束时完成,那么将来将 observable 更改为缓存处理程序的重构现在已经造成内存泄漏,因为您没有取消订阅。

取消订阅还会取消任何正在进行的请求。

像这样的陈述的问题

let sub = myObservable.subscribe(
    v => doThing(v),
    e => handle(e),
    () => sub.unsubscribe(),
)

如果 myObservable 像 BehaviorSubject 一样立即发出,那么 sub 是未定义的。我会避免像这样自行取消订阅,而是使用带有主题的 takeUntil。

const finalise$ = new Subject();

myObservable.pipe(takeUntil(finalise$)).subscribe(
    v => doThing(v),
    e => handle(e),
    () => { finalise$.next(); },
);

此代码保证是自我退订安全的。


推荐阅读