Angular/RxJs When should I unsubscribe from `Subscription`

前端 未结 22 2300
隐瞒了意图╮
隐瞒了意图╮ 2020-11-21 04:56

When should I store the Subscription instances and invoke unsubscribe() during the NgOnDestroy life cycle and when can I simply ignore them?

22条回答
  •  星月不相逢
    2020-11-21 05:28

    For observables that complete directly after emitting the result like AsyncSubject or for example observables from http requests and such you don't need to unsubscribe. It doesn't hurt to to call unsubscribe() for those, but if the observable is closed the unsubscribe method will simply not do anything:

    if (this.closed) {
      return;
    }
    

    When you have long-lived observables that emit several values over time (like for example a BehaviorSubject or a ReplaySubject) you need to unsubscribe to prevent memory leaks.

    You can easily create an observable that completes directly after emitting a result from such long lived observables using a pipe operator. In some answers here the take(1) pipe is mentioned. But I prefer the first() pipe. The difference to take(1) is that it will:

    deliver an EmptyError to the Observer's error callback if the Observable completes before any next notification was sent.

    Another advantage of the first pipe is that you can pass a predicate that will help you to return the first value that satisfies certain criteria:

    const predicate = (result: any) => { 
      // check value and return true if it is the result that satisfies your needs
      return true;
    }
    observable.pipe(first(predicate)).subscribe(observer);
    

    First will complete directly after emitting the first value (or when passing a function argument the first value that satisfies your predicate) so there is no need to unsubscribe.

    Sometimes you are not sure about whether you have a long lived observable or not. I am not saying it is good practice but you could then always add the first pipe just to make sure you won't need to manually unsubscribe. Adding an additional first pipe on an observable that will emit only one value doesn't hurt.

    During development you can use the single pipe that will fail if source observable emits several events. This can help you to explore the type of observable and whether it is necessary to unsubscribe from it or not.

    observable.pipe(single()).subscribe(observer);
    

    The first and single seem very similar, both pipes can take an optional predicate but the differences are important and nicely summarized in this stackoverflow answer here:

    First

    Will emit as soon as first item appears. Will complete right after that.

    Single

    Will fail if source observable emits several events.


    Note I tried to be as accurate and complete as possible in my answer with references to the official documentation, but please comment if something important is missing...

提交回复
热议问题