Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unsubscribing an array of subscriptions

In an Angular app, I'm managing my subscriptions by pushing them all into an array, then looping through it and unsubscribing during ngOnDestroy.

private subscriptions: Subscription[] = []
this.subscriptions.push(someObservable.subscribe(foo => bar))

My problem is that I haven't found a sufficiently clean way to handle the unsubscription. The ideal way would be a simple

ngOnDestroy () {
    this.subscriptions.forEach(subscription => subscription.unsubscribe())
}

but this doesn't work. Notably, I'm still receiving Firebase permission errors after logging out (which doesn't happen with the "working" methods). Interestingly, the exact same method does work if I pull it out into a separate class:

export class Utils {
    public static unsubscribeAll (subObject: {subscriptions: Subscription[]}) {
        subObject.subscriptions.forEach(subscription => subscription.unsubscribe())
    }
}

// ---------- back to the component

ngOnDestroy () {
    Utils.unsubscribeAll({subscriptions: this.subscriptions}) // no Firebase errors
}

but I don't really like this solution, mostly because it only works if I wrap the array in an object so it passes as a reference. The other working method I found was to write it as a for loop:

ngOnDestroy () {
    /* tslint:disable */
    for (let i = 0; i < this.subscriptions.length; i++) {
        this.subscriptions[i].unsubscribe()
    }
    /* tslint:enable */
}

but aside from the unnecessary length, it also makes TSLint complain because it thinks I should be using a for-of loop instead (which doesn't work) so I have to throw in the extra comments every time.

Currently I'm using the Utils option as the "best" solution, but I'm still not happy with it. Is there a cleaner way to do this that I'm missing?

like image 577
John Montgomery Avatar asked Jul 13 '17 17:07

John Montgomery


People also ask

What is RxJS unsubscribe?

A Subscription has one important method, unsubscribe , that takes no argument and just disposes the resource held by the subscription. In previous versions of RxJS, Subscription was called "Disposable". import { interval } from 'rxjs'; const observable = interval(1000); const subscription = observable.

Why should we unsubscribe in Angular?

In Angular applications, it's always recommended to unsubscribe the observables to gain benefits like: Avoids Memory Leaks. Aborting HTTP requests to avoid unwanted calls.

What happens if we don't unsubscribe in Angular?

🎩 Automagically Unsubscribe in Angular As you probably know when you subscribe to an observable or event in JavaScript, you usually need to unsubscribe at a certain point to release memory in the system. Otherwise, you will have a memory leak. A memory leak occurs when a section of memory that is no longer being…

Do you need to unsubscribe from Take 1?

These are called “finite subscriptions”. If you subscribe with a “take(1)”, as another example, it is finite and doesn't need to be unsubscribed.


1 Answers

Since nobody wants to post their answer as an answer, I guess I'll do it.

If you're only using the array to group them for mass unsubscribing, you can accomplish the same thing by merging them into an existing subscription. For my setup, just change the empty array to an empty subscription and change push to add:

private subscriptions = new Subscription()
this.subscriptions.add(someObservable.subscribe(foo => bar))

Then, when you want to unsubscribe from them all, just unsubscribe from the container subscription and it will handle everything.

ngOnDestroy () {
    this.subscriptions.unsubscribe()
}

Note: you can also use takeUntil on each individual subscription, but I feel like this method is simpler and makes more sense for what I'm doing.

like image 109
John Montgomery Avatar answered Sep 22 '22 23:09

John Montgomery