简体   繁体   中英

If I reassign a variable which stores an rxjs subscription, does that unsubscribe?

Here's a prototype of my code in Angular:

import { Subscription } from 'rxjs';
import { SomeClass, SomeOtherClass } from './my-component.model.ts';
import { OnDestroy } from '@angular/core';

@Component({
  selector: 'app-my-component',
  templateUrl: './my-component.component.html',
  styleUrls: ['./my-component.component.scss'],
})
export class AnalysisToolsComponent implements OnDestroy {
    private sub: Subscription;
    // instance of some class I defined in my models which has an event emitter
    instance = new SomeClass();

    // this function might get called more than once
    someFunction() {
        sub = this.instance.onEvent.subscribe( () => {})
    }

    // some other function which results in a reassignment of instance to maybe some other class
    someOtherFunction() {
        instance = new SomeOtherClass();
    }

    ngOnDestroy() {
        if (this.sub) {
            this.sub.unsubscribe();
        }
    }
}

Someone might ask why I'm reassigning the sub. It's basically because I have a child component which is a tool bar where only one tool can be selected at a time. So I only need one sub at a time to listen to events from interactions with the toolbar.

Should I be unsubbing each time I switch tool? Or can I just reassign the sub variable? My hypothesis is that the former is true. So might be nice to also get the explanation behind it if you have the answer.

Switching to a new Observable and automatically unsubscribing from the old one is best done with switchMap . To unsubscribe from an Observable when the Component gets destroyed use the takeUntil-destroy pattern.

tool$ = new BehaviorSubject<SomeTool>(new SomeTool());
private destroy$ = new Subject();

ngOnInit() {
  this.tool$.pipe(
    // use switchMap to map to a new onEvent Observable and unsubscribe from the old one
    switchMap(tool => tool.onEvent),
    // use takeUntil pattern to unsubscribe from tool$ when the component gets destroyed 
    takeUntil(this.destroy$)  
  ).subscribe( () => {} )
}

switchTool() {
  // supply a new Observable or Object containing an Observable to your Subject
  this.tool$.next(new SomeOtherTool());  // presuming SomeOtherTool extends SomeTool
}

ngOnDestroy() {
  this.destroy$.next();
  this.destroy$.complete();
}

you can unsubscribe something like below,

private sub: Subscription[] = [];

...
this.sub.push(this.instance.onEvent.subscribe( () => {}));
...

ngOnDestroy() {
  // prevent memory leak when component destroyed
  this.subscriptions.forEach(s => s.unsubscribe());
}

can I just reassign the sub variable?

It's not needed with this approach

It will unsubscribe() all the subscriptions held by the Subscription .

Are all of these observables being created in the component? If so then when the component is destroyed then all the properties fall into garbage collection with it. You get memory leaks from subscription to observables that are not garbage collected at the same time the component is destroyed.

If your component instantiates an observable and nothing else is holding a reference to that observable then unsubscribing is unnecessary as the observable falls into garbage collection with the component.

An observable that still has active references like in a service will cause memory leaks if your component is still subscribed and the component cannot be garbage collected as the subscriptions are still active on the observable in the service.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM