【问题标题】:Get all current (active) subscriptions获取所有当前(活动)订阅
【发布时间】:2018-04-12 22:23:14
【问题描述】:

是否可以在不手动存储的情况下获取所有“活动”订阅?

我想unsubscribe所有“活动”订阅,不想在数组或变量中引用它们。

【问题讨论】:

  • 你能完成 observable 吗?通常,如果我想取消订阅所有订阅者,那么我就完成了 observable。这对你来说可能不是真的。完成 observable 将关闭您的所有订阅。
  • @bygrace 我可以完成所有的 observables,但目标是避免这种情况。一些 observables 可能需要很长时间,我想对其进行优化。
  • 请问可以扩大动机吗?
  • @RichardMatsen 我需要更改组件(角度 2)并希望确保没有任何待处理。我可以将每个订阅保存在一个数组中,但我想在切换视图之前找到一种更简单、更简洁的方式来取消订阅

标签: angular rxjs


【解决方案1】:

我取决于您使用的是 Subject 还是 Observable,但可能无法“自动”执行此操作。

可观察的

我认为您不能拥有“订阅的 Observable”之类的东西,因为您要么存储 Observable 要么存储订阅:

const source = Observable.of(...)
  .map(...);

const subscription = source
  .subscribe();

这里source 代表一个 Observable,subscription 代表一个订阅。

请注意,您可以拥有一个存储多个其他订阅的 Subscription 实例:

const subscriptions = new Subscription();

const sub1 = Observable...subscribe();
const sub2 = Observable...subscribe();
const sub3 = Observable...subscribe();

subscriptions.add(sub1).add(sub2).add(sub3);

// Then unsubscribe all of them with a single 
subscriptions.unsubscribe();

主题

如果您正在使用主题,它们本身确实有 unsubscribe 方法,请参阅 https://github.com/ReactiveX/rxjs/blob/master/src/Subject.ts#L96

但是请注意,这会使主题“停止”,有关更多信息,请参阅https://medium.com/@martin.sikora/rxjs-subjects-and-their-internal-state-7cfdee905156

【讨论】:

  • 您的方法意味着在数组中“手动”添加每个可观察对象......这是我想要避免的。
  • 我尝试在一个有两个订阅的主题上调用unsubscribe,它抛出了一个ObjectUnsubscribedError
  • Ref this question ObjectUnsubscribedError when trying to prevent subscribing twice 基本上表明您不能为此目的使用 Subject.unsubscribe() ,但没有解释原因。
  • 你能做一个演示吗? unsubscribe() 方法本身不会抛出任何东西
  • 您可以取消订阅 Subject.observers 而不会受到惩罚。这有点棘手,因为每个取消订阅都会改变观察者数组(需要使用while(subject.observers.length)但是我对使用这种方法有疑问。
【解决方案2】:

我认为基本问题是 Observable(除了 Subject 和衍生物)不保留对其观察者的引用。

如果没有内置引用,您需要以某种形式在外部处理它们。

我认为你能做到的最好的事情是创建一个可重用的订阅“覆盖”来包装机制,尽管我怀疑它是否值得。

import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription';

const subscribeAndGuard = function(component, fnData, fnError = null, fnComplete = null) {

  // Define the subscription
  const sub: Subscription = this.subscribe(fnData, fnError, fnComplete);

  // Wrap component's onDestroy
  if (!component.ngOnDestroy) {
    throw new Error('To use subscribeAndGuard, the component must implement ngOnDestroy');
  }
  const saved_OnDestroy = component.ngOnDestroy;
  component.ngOnDestroy = () => {
    console.log('subscribeAndGuard.onDestroy');
    sub.unsubscribe();
    // Note: need to put original back in place
    // otherwise 'this' is undefined in component.ngOnDestroy
    component.ngOnDestroy = saved_OnDestroy;
    component.ngOnDestroy();

  };

  return sub;
};

// Create an Observable extension
Observable.prototype.subscribeAndGuard = subscribeAndGuard;

// Ref: https://www.typescriptlang.org/docs/handbook/declaration-merging.html
declare module 'rxjs/Observable' {
  interface Observable<T> {
    subscribeAndGuard: typeof subscribeAndGuard;
  }
}

参考这个问题Angular/RxJs When should I unsubscribe from Subscription

【讨论】:

    【解决方案3】:

    您可以只存储一个订阅,然后添加到其中。

    private _subscriptions = new Subscription();   // yes you can do this!
    

    然后添加到它

    _subscriptions.add(
        this.layoutManager.width$.subscribe((w) => {
    
            // any nested subscriptions can also use this mechanism
            _subscriptions.add(...);
        });
    

    然后在ngOnDestroy() 中,您只需致电_subscriptions.unsubscribe();

    我一直在尝试用一种“聪明”的方式来做到这一点,但坦率地说,我已经过度设计了它(包括日志记录),这是我遇到的最简单的方式。

    【讨论】:

    • 好吧,如果您遇到任何事情,请更新 b/c 真的,我还没有找到的一件事是如何在再次订阅之前取消订阅,对于需要此功能的单个方法以“聪明”的方式没有额外的变量来取消订阅(如果存在)......
    • 我不确定您在寻找什么。除非你在谈论一个异步函数(包含 await),否则你会通过在方法末尾取消订阅 observable 来破坏 RxJs 的目的。如果您正在执行 take(1) 并试图获得某物的即时价值,那么您无论如何都不需要取消订阅。我使用了一个辅助服务,它的好处是在组件被销毁时自动调用 ngOndestroy,但它带来了更多的复杂性。
    • 这就是我所说的——最终只是扩展了功能。 wiki 和 stackblitz 应该解释 :) 感谢您的关注! github.com/dontboyle/rxjs-serial-subscription/wiki
    【解决方案4】:

    是的。如果您使用的是Subjectrxjs 对象,只需调用.observers 属性即可。

    希望这会有所帮助。

    【讨论】:

    • 遗憾的是,.observers 已被弃用,将在 v8 中成为内部版本。
    • @squidfunk 非常感谢。
    【解决方案5】:

    其中一个选项是结合使用 takeUntil 和 Subject 来停止所有 (Observable) 订阅。

    terminator$: Subject<boolean> = new Subject();
    
    Observable.timer(1000)
      .do(i => console.log(`timer 1: ${i}`))
      .takeUntil(terminator$)
      .subscribe();
    
    Observable.timer(5000)
      .do(i => console.log(`timer 2: ${i}`))
      .takeUntil(terminator$)
      .subscribe();
    
    const stopSubscriptions = () => terminator$.next(true);
    

    【讨论】:

      【解决方案6】:

      最简单的方法是使用 ngx-auto-unsubscribe。 有了这个装饰器,你不应该放 unsubscribe(),这是自动完成的

      使用这个你只需要声明onDestroy,你不需要在这个里面放任何东西。

      它很容易使用,我鼓励你使用它。

      Npm installation

      Official documentation

      【讨论】:

        【解决方案7】:

        您可以继承一个实现 OnDestroy 接口的 Base 组件并保留一个数组来存储所有订阅,最后在销毁时您可以找到带有订阅实例的对象并取消订阅所有。下面我来写代码吧。

        1. 创建一个实现 OnInit、ODestroy 的基类
        export class BaseComponent implements OnInit, OnDestroy {
        
          subscriptions: Subscription[] = [];
        
          ngOnInit(): void {
          }
        
          ngOnDestroy(): void {
            console.log('OnDestory - Baselass');
            this.subscribers.forEach(sub => {
              sub.unsubscribe();
              console.log('Unsub');
            })
          }
        
        
           addObserver(subscription: Subscription) {
              this.subscribers.push(subscription);
           }
        }
        
        1. 创建组件并继承基类
        export class SomeComponent extends BaseComponent implements OnInit, OnDestroy {
        
            constructor(private someService: SomeService) {
              super();
            }
        
            ngOnInit(): void {
              super.ngOnInit();
            }
        
            ngOnDestroy(): void {
              super.ngOnDestroy()
            }
        
            private initObservers() {
              super.addObserver(this.someService.someObservable$.subscribe(res => {
        
              }));
            }
        
            
        }
        

        就是这样,您现在不必担心手动取消订阅,BaseComponent 会负责处理。

        重点:- 将订阅传递给超类是必要的,它保留列表并取消订阅组件销毁生命周期事件的所有订阅。

        super.addObserver(this.someService.someObservable$.subscribe(res => {
        
        }));
        

        谢谢!!

        【讨论】:

          猜你喜欢
          • 2015-01-27
          • 1970-01-01
          • 2017-07-13
          • 1970-01-01
          • 2022-09-27
          • 1970-01-01
          • 2020-12-16
          • 2014-05-06
          • 1970-01-01
          相关资源
          最近更新 更多