Unsubscribing from RxJS Observables with Angular

by ヒーロー
820 views

Có thể bạn đã biết …

Problem

Đối với Angular thì RxJS như là xương sống của ứng dụng vậy. RxJS sử dụng khái niệm Observables và Observers, trong đó thì Observables là data sources và Observer là người dùng data. Mỗi khi Observable trả về values, thì ngay lập tức nó sẽ inform cho Observer và các Observer này sẽ sử lý dữ liệu trả về thông qua các operator. Làm việc với Observables nếu không khéo sẽ có khả năng gây memory leak cho ứng dụng. Đó là khi bạn subscribe 1 Observable mà sau đó không unsubscribe nó.

Solution

Ta sẽ phải thủ công unsubscribe tất cả các custom Observables trong khi destroyed các component/directive. Nơi tốt nhất để unsubscribe đó là handle trong function handle event OnDestroy. Tuy nhiên, để có thể tự động unsubscribe các subscriptions có 3 cách sau đây:

  • unsubscribe thông qua subscription object
  • takeUntil operator
  • async pipe

Unsubscribe

export class UnsubscribeCardComponent implements OnInit, OnDestroy {
  message: string;
  subscription: Subscription;
  constructor(private upperCaseService: UpperCaseService) {}
 
  ngOnInit() {
    this.subscription = this.upperCaseService.getUpperCaseMessage()
      .subscribe((message: string) => this.message = message);
  }
 
  ngOnDestroy(): void {this.subscription.unsubscribe();}
}	

Cách này là dùng 1 đối tượng Subscription để hold resource và dispose nó khi gọi hàm unsubscribe.

TakeUntil

export class TakeUntilCardComponent implements OnInit, OnDestroy {
  message: string;
  private unsubscribe$ = new Subject();
  constructor(private upperCaseService: UpperCaseService) {}
 
  ngOnInit() {
    this.upperCaseService.getUpperCaseMessage()
      .takeUntil(this.unsubscribe$)
      .subscribe((message: string) => this.message = message);
  }
 
  ngOnDestroy(): void {
    this.unsubscribe$.next();
    this.unsubscribe$.complete();
  }
}

takeUntil sẽ nhận Observable như là 1 tham số, và nó sẽ hủy subscription khi Observable bắn ra giá trị hoặc bị terminate

AsyncPipe

export class AsyncPipeCardComponent implements OnInit {
  messageSubscription: Observable<string>;
  constructor(private upperCaseService: UpperCaseService) {}
 
  ngOnInit() {
    this.messageSubscription = this.upperCaseService.getUpperCaseMessage();
  }
}

HTML template:
<p>{{messageSubscription | async}}</p>

async pipe sẽ subscribe tới 1 Observable và trả về giá trị mới nhất khi nhận được từ Observable ném ra. Khi component bị destroyed thì async pipe sẽ tự động unsubscribe.

Kết luận

Khi 1 component/directive bị destroyed, tất các các custom Observable cần phải có thao tác unsubscribe. Qua qua trình tìm hiểu, cũng như làm Angular mình nhận thấy là: Async pipe là solution tốt nhất vì mọi thì đều tự động được thực hiện, tuy nhiên không phải hoàn cảnh nào cũng dùng async pipe được. Khi không dùng được async pipe bạn hãy chuyền qua dùng takeUntil operator.

Leave a Comment

* By using this form you agree with the storage and handling of your data by this website.