RXJS - 获取所有当前(活动)订阅

时间:2017-10-31 16:57:45

标签: angular rxjs

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

我想unsubscribe所有“有效”订阅,并且不希望在数组或变量中引用它们。

7 个答案:

答案 0 :(得分:7)

我取决于您使用的是主题还是观察者,但可能无法“自动”执行此操作。

观测量

我认为你不能拥有“订阅的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

答案 1 :(得分:4)

其中一种选择是将takeUntil与Subject结合使用以停止所有(可观察)订阅。

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);

答案 2 :(得分: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 :(得分:1)

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

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();

我一直在尝试做一个“聪明”的方法来做到这一点,但是坦率地说,我对它进行了过多的设计(包括日志记录),这是我遇到的最简单的方法。

答案 4 :(得分:1)

是的。如果您使用的是.observers的{​​{1}}对象,只需调用Subject属性。

希望这会有所帮助。

答案 5 :(得分:0)

最简单的方法是使用 ngx-auto-unsubscribe 。 使用此装饰器,您不应放置unsubscribe(),这是自动完成的

要使用此功能,只需声明 onDestroy ,则无需在其中添加任何内容。

它非常易于使用,我鼓励您使用它。

Npm installation

Official documentation

答案 6 :(得分:0)

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

  1. 创建一个实现Onesit,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. 创建一个组件并继承Base类
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 => {

      }));
    }

    
}

就是这样,您现在无需担心手动退订SubComponent的麻烦,BaseComponent会解决这个问题。

重要点: 必须将订阅传递给超类,这样才能保留列表并取消订阅组件销毁生命周期事件中的所有订阅。

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

}));

谢谢!