7

In an Angular 7 Component, I use the RxJS takeUntil() to properly unsubscribe on observable subscriptions.

  • What happens when the this.destroy$.next() is missing in the method ngOnDestroy (see sample below)? Will it still unsubscribe properly?
  • What happens when the this.destroy$.complete() is missing in the method ngOnDestroy (see sample below)? Will it still unsubscribe properly?
  • Is there any way to enforce that pattern with takeUntil() to unsubscribe is properly used (e.g. tslint rule, npm package)?

@Component({
    selector: 'app-flights',
    templateUrl: './flights.component.html'
})
export class FlightsComponent implements OnDestroy, OnInit {
    private readonly destroy$ = new Subject();

    public flights: FlightModel[];

    constructor(private readonly flightService: FlightService) { }

    ngOnInit() {
        this.flightService.getAll()
            .pipe(takeUntil(this.destroy$))
            .subscribe(flights => this.flights = flights);
    }

    ngOnDestroy() {
        this.destroy$.next();
        this.destroy$.complete();
    }
}
Horace P. Greeley
  • 882
  • 1
  • 10
  • 18

4 Answers4

3
  1. takeUntil takes next as emission. If only complete() called it won't unsubscribe

try this out:

const a=new Subject();
interval(1000).pipe(takeUntil(a)).subscribe(console.log);
timer(3000).subscribe(_=>a.complete())
  1. this.destroy$ is still in the memory and won't get garbage collected
  2. Not that i am aware of

Please also take a look here to avoid memory leak when using takeUntil.

https://medium.com/angular-in-depth/rxjs-avoiding-takeuntil-leaks-fb5182d047ef

Personally I prefer explicit unsubscribe upon destroy.

Marcos Dimitrio
  • 6,651
  • 5
  • 38
  • 62
Fan Cheung
  • 10,745
  • 3
  • 17
  • 39
  • #2 is wrong. See https://stackoverflow.com/questions/57007118/do-i-need-to-complete-takeuntil-subject-inside-ngondestroy for why. – Shawn May 26 '23 at 21:07
  • We are just talking about when subject can be totally become stale and garbage collected, and also imagine if this component is an application wrapper and exist throughout all pages. – Fan Cheung May 29 '23 at 13:11
  • OP specifically asked about calling it in ngOnDestroy (component is being removed) with a clear code example that doesn't show any other reference to `this.destroy$`. Therefore that answer can be misleading. – Shawn May 30 '23 at 19:55
  • in that case i have overlooked the actual use case scenario, but i would still suggest to add .complete() ` as a good practice. if this subject is being subscribed by other component or service there will still be memory leak even if component is removed from my understanding. – Fan Cheung May 31 '23 at 07:26
  • Right. But again there's no sign of outside reference in OP's example, and it's not a typical case with this approach. I would still suggest editing the answer and clarifying the confusion. – Shawn Jun 02 '23 at 00:38
2

Here's a simpler approach:

private readonly destroy$ = new Subject<boolean>();

...

ngOnDestroy() {
    this.destroy$.next(true);
    this.destroy$.unsubscribe();
}
Paul Story
  • 582
  • 4
  • 10
0

this.destroy$.next() triggers the Subject which triggers the takeUntil operator which completes the flightService.getAll() subscription.

this.destroy$.complete() completes the destroy$ Subject when component is destroyed.

noririco
  • 765
  • 6
  • 15
0

Hi use takeWhile instead of takeUntil.

@Component({
    selector: 'app-flights',
    templateUrl: './flights.component.html'
})
export class FlightsComponent implements OnDestroy, OnInit {
    private readonly destroy$ = new Subject();
    alive = true;
    public flights: FlightModel[];

    constructor(private readonly flightService: FlightService) { }

    ngOnInit() {
        this.flightService.getAll()
            .pipe(takeWhile(() => this.alive))
            .subscribe(flights => this.flights = flights);
    }

    ngOnDestroy() {
        this.alive = false;
        this.destroy$.complete();
    }
}
upinder kumar
  • 819
  • 6
  • 8
  • 1
    Why prefer takeWhile here? Not sure this inversion to the accepted answer gives much of an additional benefit. The destroy$ property of your class is superfluous too – bzzWomp Sep 14 '22 at 12:30