Do I need to complete a Subject for it to be garbage collected?

10,305

If you look at the source for Subject.complete, you'll find the answer:

complete() {
  if (this.closed) {
    throw new ObjectUnsubscribedError();
  }
  this.isStopped = true;
  const { observers } = this;
  const len = observers.length;
  const copy = observers.slice();
  for (let i = 0; i < len; i++) {
    copy[i].complete();
  }
  this.observers.length = 0;
}

Calling complete notifies any observers and then clears the array of observers. Unless you have an observer/subscriber that has a reference to the Subject, there is nothing in the complete implementation that would affect whether or not the Subject could be garbage collected.

RxJS pushes notifications to subscribers. Subscribers don't hold references to the observables; it's the other way around. So, unless you've explicitly created a subscriber that holds a reference to the Subject - via a closure or some other mechanism - there's no need to call complete for garbage-collection purposes.

Share:
10,305

Related videos on Youtube

Sean Walsh
Author by

Sean Walsh

Find me on Twitter as THEseanwalsh or on GitHub as s992.

Updated on September 15, 2022

Comments

  • Sean Walsh
    Sean Walsh over 1 year

    I follow a cleanup pattern in my Angular components that looks like this:

    class SomeComponent implements OnInit, OnDestroy {
        private destroy$ = new Subject();
    
        ngOnInit() {
            service.someStream().takeUntil(this.destroy$).subscribe(doSomething);
        }
    
        ngOnDestroy() {
            this.destroy$.next(true);
        }
    }
    

    This has the benefit of automatically unsubscribing when the component is destroyed.

    My question is: Does a reference to destroy$ stick around indefinitely because I haven't called this.destroy$.complete(), or will it get GC'ed when the parent class is collected?

    • nej_simon
      nej_simon over 4 years
      @paulpdaniels If you have multiple subscriptions you'd have to keep references to each of them and call unsubscribe on each in sequence. By using pattern above you can have a single subject that unsubscribes from them all at once. The result is less, and more readable, code.
    • oomer
      oomer about 2 years
      The OP is about garbage collecting the subject, why are the comments discussing how to garbage collect subscriptions ?
    • martin
      martin
      Even though you're not directly calling complete() on the Subject you complete the chain with the takeUntil operator which sends the complete signal and makes each operator to recursively unsubscribe. So it shouldn't matter whether the complete signal comes from the Subject or somewhere further down the chain.
  • Sean Walsh
    Sean Walsh almost 7 years
    Hey @cartant, thank you for your answer. Just so I'm clear, does having my Subject in a takeUntil count as an observer/subscriber having a reference to it? I assume no, because that subject is unsubscribed from once it emits, but I just want to make sure.
  • cartant
    cartant almost 7 years
    The use in takeUntil is fine, as the subject's reference to the observer will be removed via the takeUntil-initiated unsubscription. It's possible that the observer's reference would prevent the subject from being collected - depending upon what's referencing the observer - but that's a separate issue and is not related to whether or not complete is called on the subject.
  • kos
    kos about 5 years
    @cartant, then this is a precaution, not a necessity take-until-destroy.ts#L26, right? I was just researching the same thing as OP, so please don't consider this as annoyance.
  • oomer
    oomer about 2 years
    So, basically calling subject.complete() clears the list of observers / subscriptions maintained inside the subject, it does not garbage collect the subject itself ?