user1763590
user1763590

Reputation: 137

Is it necessary to unsubscribe everytime I subscribe

I am trying to determining what to do with the following code

let sub = myObservable.subscribe(
    v => doThing(v),
    e => handle(e),
    () => sub.unsubscribe(),
)

The issue is 1. This code is incorrect because of myObservable completed synchronously, an NPE would be thrown on completion. 2. Even though I suspect that the unsubscribe call here is good practice. I can't help but feel it might not be necessary because I have not see it done anywhere else.

I have read this article https://blog.angularindepth.com/why-you-have-to-unsubscribe-from-observable-92502d5639d0 but it actually leaves me more confused than when I started.

If I do

let subA = myObservable.pipe(take(1)).subscribe()
let subB = myObservable.pipe(takeUntil(foo)).subscribe()

Do I not need to unsubscribe subA and subB anymore?

how about subC over here?

let subC = myObservable.pipe(finalize(() => cleanupOtherResources())).subscribe()

Or do I have to add all subscription into a list in every class that calls subscribe() on any BehaviorSubject and unsubscribe them at once?

Thanks!

Upvotes: 0

Views: 82

Answers (1)

Adrian Brand
Adrian Brand

Reputation: 21628

It is always best practice to unsubscribe. takeUntil is fine to use if you know that the clean up method of your class actually emits on the cleanup observable. take is not always guaranteed that the observable has emitted. There may be cases where you know that observable will definitely emit at least once but there is still a possibility that a leak has been created.

The problem with assuming that an observable will complete is that you don't know if the internals of the service returning the observable change. If you assume that the observable is a http request and completes at the end of the request then a future refactor that changes the observable to a cache handler has now created a memory leak because you didn't unsubscribe.

Unsubscribing also cancels any on going requests.

The problem with statements like

let sub = myObservable.subscribe(
    v => doThing(v),
    e => handle(e),
    () => sub.unsubscribe(),
)

If myObservable emits instantly like a BehaviorSubject would then sub is undefined. I would avoid self unsubscribing like that and instead use a takeUntil with a subject.

const finalise$ = new Subject();

myObservable.pipe(takeUntil(finalise$)).subscribe(
    v => doThing(v),
    e => handle(e),
    () => { finalise$.next(); },
);

This code is guaranteed to be self unsubscribe safe.

Upvotes: 1

Related Questions