退订ReplaySubject作为asObservable()返回;

时间:2018-09-03 16:00:36

标签: angular typescript rxjs

标题

如果您基本上有相同的问题,并且上下文是Angular,则可能需要阅读答案中的所有注释以获取更多上下文。

此问题的简短版本

进行let observe$ = someReplaySubject.asObservable()时,是否不再需要取消订阅observe$?换句话说,我们可以从多个Angular组件实例中调用let observe$ = someReplaySubject.asObservable(),而不必担心从notify实例到相应的Observable的连接吗?

假设

如果我们有一个ReplaySubject<Todo[]>实例(我们叫它rxTodo,我们可以通过以下方式从Angular组件中订阅它:

let todoObs$:Observable<Todo[]> = rxTodo$.asObservable(),那么即使该组件被破坏,在每个组件中创建的todoObs$引用也将悬而未决,直到组件本身被破坏。

背景

我正在尝试针对Angular的Store API,并且我有一个重放主题,该主题将更改广播到商店的各个部分。这是允许订阅发生的方法(notifyCount跟踪订阅,因此,如果没有订阅,我们就不会打扰通知):

  /**
   * Subscribe to receive slice updates.
   * @example
     <pre>
    let todos$ = slice.subscribe();
    </pre>
  */
  public subscribe(): Observable<E[]> {
    this.notifyCount++;
    return this.notify.asObservable();
  }

以上,我尝试遵循建议的最佳实践,而不是从Observable返回ReplaySubject

这是相应的unsubscribe方法:

  /**
   * Unsubscribe from slice updates.
   * 
   * @example 
    <pre>
      slice.unsubscribe(o);
    </pre>
  */
  public unsubscribe(o: ReplaySubject<E[]>) {
    o.unsubscribe();
    this.notifyCount--;
  }

为了使o,我必须将ReplaySubject自变量设置为unsubscribe类型。但是,这与Observable方法返回的subscribe类型冲突。

尝试进行这样的测试时:

incompleteSlice.unsubscribe(incomplete$);

返回的消息是这样的:

  

[ts]   无法将类型“可观察”的参数分配给类型“ ReplaySubject”的参数。     类型“可观察”中缺少属性“调度程序”。   让incomplete $:可观察

关于如何解决此问题的任何想法?

更新

我想到的一个显而易见的想法是,也许返回asObservable意味着我们不再需要实际上从该可观察值中unsubscribe。如果Angular组件被破坏,我们可以悬空吗?

1 个答案:

答案 0 :(得分:2)

我认为您对退订SubscriptionSubject感到困惑。

当组件被销毁时,Angular中实际建议的是取消订阅任何打开的SubscriptionSubscription返回了Observable.subscribe。取消订阅后,它不再从可观察的来源接收值,这是大多数情况下想要的。

退订Subject会有不同的效果。它将主题切换到closed状态,在此状态下您将无法再调用next或订阅它。您可以look directly at the source code来了解发生了什么。

无法退订Observable,这部分是您收到错误的原因。

为了遵循建议,您应该列出所有订阅,即将每个订阅添加到稍后可以访问的列表中,如下所示:

this.subscriptions$.push(obs$.subscribe...))

然后在销毁组件时,调用:

this.subscriptions$.forEach(sub -> sub.unsubscribe());

但更好的是,recommended by Core Developer Ben Lesh in this article不是强制调用unsubscribe,而是利用takeUntil运算符。

There is a reference implementation on StackOverflow用于将此模式与Angular一起使用,您可以将其用作起点。