You never need to unsubscribe from a completed observable. Observables complete either with a complete() or an error() call to their observer(s). That's part of the contract of an observable.
Consider the following example.
const sub = interval(250).pipe(
take(4),
map(x => x + 1)
).subscribe({
next: console.log,
complete: () => console.log("This observable completed naturally"),
err: _ => console.log("This observable completed with an error")
});
console.log("Sub is closed, no need to unsubscribe? " + sub.closed);
setTimeout(() => {
console.log("Sub is closed, no need to unsubscribe? " + sub.closed);
}, 1250);
console output:
Sub is closed, no need to unsubscribe? false
1
2
3
4
This observable completed naturally
Sub is closed, no need to unsubscribe? true
This demonstrates that observables that will complete do not need to be unsubscribed and do not create memory leaks. The issue is with observables that are long-lived (like an interval that doesn't have a take
, takeWhile
, takeWhen
, ect operator).
In angular, for example, some observables need to be around for as long as the component is there, but no longer. They're linked to a components life-cycle. The issue is that forgetting to unsubscribe to observables like these (ones that do not complete
on their own) will cause a memory leak.
Synchronous Example:
of("Hello There").subscribe({
next: console.log,
complete: () => console.log("This observable completed naturally"),
err: _ => console.log("This observable completed with an error")
});
You do not need to unsubscribe to this observable. In fact, because it runs synchronously, it will be closed before it is possible for you to unsubscribe.
const sub = of(1).subscribe();
console.log(sub.closed); // output: true
Unsubscribe required example:
const sub = interval(1000).subscribe(console.log);
setTimeout(() => {
console.log("Sub is closed: " + sub.closed);
sub.unsubscribe();
console.log("Sub is closed: " + sub.closed);
}, 60 x 60 x 1000);
Here we start an observable, then we wait an hour to see if it's closed. Then we unsubscribe and check if it's closed. This interval with run forever until it is explicitly unsubscribed.
console output:
0
1
2
... [skipping ahead]
3596
3597
3598
3599
Sub is closed: false
Sub is closed: true