Angular/RxJs When should I unsubscribe from `Subscription`

前端 未结 22 2201
隐瞒了意图╮
隐瞒了意图╮ 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:18

    You don't need to have bunch of subscriptions and unsubscribe manually. Use Subject and takeUntil combo to handle subscriptions like a boss:

    import { Subject } from "rxjs"
    import { takeUntil } from "rxjs/operators"
    
    @Component({
      moduleId: __moduleName,
      selector: "my-view",
      templateUrl: "../views/view-route.view.html"
    })
    export class ViewRouteComponent implements OnInit, OnDestroy {
      componentDestroyed$: Subject = new Subject()
    
      constructor(private titleService: TitleService) {}
    
      ngOnInit() {
        this.titleService.emitter1$
          .pipe(takeUntil(this.componentDestroyed$))
          .subscribe((data: any) => { /* ... do something 1 */ })
    
        this.titleService.emitter2$
          .pipe(takeUntil(this.componentDestroyed$))
          .subscribe((data: any) => { /* ... do something 2 */ })
    
        //...
    
        this.titleService.emitterN$
          .pipe(takeUntil(this.componentDestroyed$))
          .subscribe((data: any) => { /* ... do something N */ })
      }
    
      ngOnDestroy() {
        this.componentDestroyed$.next(true)
        this.componentDestroyed$.complete()
      }
    }
    

    Alternative approach, which was proposed by @acumartini in comments, uses takeWhile instead of takeUntil. You may prefer it, but mind that this way your Observable execution will not be cancelled on ngDestroy of your component (e.g. when you make time consuming calculations or wait for data from server). Method, which is based on takeUntil, doesn't have this drawback and leads to immediate cancellation of request. Thanks to @AlexChe for detailed explanation in comments.

    So here is the code:

    @Component({
      moduleId: __moduleName,
      selector: "my-view",
      templateUrl: "../views/view-route.view.html"
    })
    export class ViewRouteComponent implements OnInit, OnDestroy {
      alive: boolean = true
    
      constructor(private titleService: TitleService) {}
    
      ngOnInit() {
        this.titleService.emitter1$
          .pipe(takeWhile(() => this.alive))
          .subscribe((data: any) => { /* ... do something 1 */ })
    
        this.titleService.emitter2$
          .pipe(takeWhile(() => this.alive))
          .subscribe((data: any) => { /* ... do something 2 */ })
    
        // ...
    
        this.titleService.emitterN$
          .pipe(takeWhile(() => this.alive))
          .subscribe((data: any) => { /* ... do something N */ })
      }
    
      ngOnDestroy() {
        this.alive = false
      }
    }
    

提交回复
热议问题