There is no need to manually unsubscribe from a completed observable. Observables either complete naturally or with an error, according to their contract.
Let's look at an example to better understand this concept.
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("Is subscription closed? " + sub.closed);
setTimeout(() => {
console.log("Is subscription closed? " + sub.closed);
}, 1250);
Output:
Subscription closed? false
1
2
3
4
This observable completed naturally
Subscription closed? true
This demonstrates that observables that will complete themselves do not require manual unsubscribing and do not lead to memory leaks. The concern arises with long-lived observables (e.g., an interval without completion).
In Angular, some observables are tied to a component's lifecycle and must be unsubscribed when the component is destroyed to prevent memory leaks.
Synchronous Scenario:
of("Hello There").subscribe({
next: console.log,
complete: () => console.log("This observable completed naturally"),
err: _ => console.log("This observable completed with an error")
});
You don't need to unsubscribe from this synchronous observable as it completes before you can even unsubscribe.
const sub = of(1).subscribe();
console.log(sub.closed); // output: true
Example Requiring Unsubscription:
const sub = interval(1000).subscribe(console.log);
setTimeout(() => {
console.log("Is subscription closed: " + sub.closed);
sub.unsubscribe();
console.log("Is subscription closed: " + sub.closed);
}, 3600000);
In this case, we start an interval observable which runs indefinitely until explicitly unsubscribed after an hour.
Output:
0
1
2
... [skipping ahead]
3596
3597
3598
3599
Is subscription closed: false
Is subscription closed: true