SUBSCRIBE NEWSLETTERS

Xem nhiều nhất

Các cách để unsubscribe Observables trong Angular

Các cách để unsubscribe Observables trong Angular

Ngày đăng 11/8/2020
5 phút đọc
584 lượt xem
Duclux.Com
Tác giảDucLux.Com

Trong bài viết này mình sẽ giới thiệu một số cách unsubscribe một Observable thường được sử dụng trong Angular.

Tại sao chúng ta cần unsubscribe các Observables ?

Khi chúng ta subscribe một observable, chúng tạo ra một Subscription. Nó sẽ luôn subscribe cho tới khi observable completed hoặc xảy ra lỗi. Nếu chúng ta không unsubscribe sẽ dẫn tới ứng dụng quá tải do Memory Leak.

1. Sử dụng method unsubscribe

Method unsubscribe() có sẵn trong một subscription. Sử dụng nó khi cần hủy theo dõi một observable. Đơn giản, bạn chỉ cần gọi unsubscribe() tại bất cứ khi nào bạn muốn hủy đăng ký theo dõi.

Ví dụ: 

import { interval } from 'rxjs/operators'; 
@Component({...})
export class AppComponent implements OnInit, OnDestroy {
private subscription: Subscription;
ngOnInit () {
const interval$ = interval(1000);
this.subscription = interval$.subscribe(console.log);
}
ngOnDestroy {
if (this.subscription) {
this.subscription.unsubscribe();
}
}
}

Đoạn trên nghĩa là chúng ta subscribe 1 interval trong Oninit, khi component này bị destroy, chúng ta muốn hủy subscription đi, check if (this.subscription) để đảm bảo chương trình không sinh ra lỗi, vì trong một số trường hợp subscription không tồn tại ví dụ như khi bạn run SSR.

Trường hợp nếu có nhiều hơn 1 subscription thì làm thế nào?

Chúng ta có thể tạo ra một mảng subscriptions, sẽ loop gọi unsubscribe từng phần tử. Hoặc chúng ta có thể add vào 1 subscription.

import { interval } from 'rxjs/operators'; 
@Component({...})
export class AppComponent implements OnInit, OnDestroy {
private subscriptions: Subscription[] = [];
ngOnInit () {
const interval1$ = interval(1000);
const interval2$ = interval(2000);
const subscription1= interval1$.subscribe(console.log);
const subscription2 = interval2$.subscribe(console.log);
this.subscriptions.push(subscription1);
this.subscriptions.push(subscription2);
}
ngOnDestroy {
this.subscriptions.forEach(sub => sub.unsubscribe());
}
}
import { interval } from 'rxjs/operators'; 
@Component({...})
export class AppComponent implements OnInit, OnDestroy {
private subscription: Subscription;
ngOnInit () {
const interval1$ = interval(1000);
const interval2$ = interval(2000);
const subscription1= interval1$.subscribe(console.log);
const subscription2 = interval2$.subscribe(console.log);
this.subscriptions.add(subscription1);
this.subscriptions.add(subscription2);
}
ngOnDestroy {
if (this.subscription) {
this.subscription.unsubscribe();
}
}
}

2. Sử dụng take, takeUntil, takeWhile

- take(number): Observable sẽ được unsubscribe khi phát đủ number tín hiệu được truyền trong take, (trong ví dụ bên dưới 3 values).

import { interval } from 'rxjs/operators'; 
@Component({...})
export class AppComponent implements OnInit {
ngOnInit () {
const subscription2 = interval2$.pipe(take(3)).subscribe(console.log);
}
}
Cần lưu ý nếu dùng take phải tính toán tới trường hợp observable không emit value thì subscription vẫn tồn tại.  

Vậy nên bạn nên sử dụng take(n) để giới hạn số tín hiệu nhận từ observable không nên dùng để unsubscribe. Best pratice vẫn là unsub nó khi component destroy bằng cách ở trên hoặc bằng cách dưới đây.

- takeUntil(signal$):

Đây là cách mình sử dụng thường xuyên, takeUntil nhận vào một observable signal$, khi signal emit một giá trị bất kì (kể cả falsy như null, undefined, false...) thì takeUntil sẽ tiến hành ubsub observable hiện tại.

import { interval } from 'rxjs/operators'; 
@Component({...})
export class AppComponent implements OnInit, OnDestroy {
private destroy$: Subject = new Subject();
ngOnInit () {
const interval1$ = interval(1000);
const subscription1=
interval1$.pipe(takeUntil(this.destroy$)).subscribe(console.log);
}
ngOnDestroy {
this.destroy$.next();
this.destroy$.complete();
}
}

- takeWhile(predicate):

Observable có gắn operator takeWhile sẽ emit value cho tới khi không còn thỏa mãn điều kiện mà hàm predicate trả về nữa. Tương tự như take chúng ta vẫn nên unsub observable khi component destroy ngay cả khi dùng takeWhile.

import { Subscription } from 'rxjs'; 
import { interval } from 'rxjs/operators';
@Component({...})
export class AppComponent implements OnInit, OnDestroy {
private subscription: Subscription;
ngOnInit () {
const interval1$ = interval(1000);
this.subscription= interval1$.pipe(takeWhile(x => x < 5).subscribe(console.log);
}
ngOnDestroy {
if (this.subscription) {
this.subscription.unsubscribe();
}
}
}

Ở ví dụ trên, subscription sẽ nhận value cho tới 4, value có giá trị 5 emit ra gặp takeWhile sẽ unsubscribe luôn. 

Trên đây là một số cách unsubscribe mình thường dùng, ngoài ra còn một số cách khác nữa nhưng ít sử dụng, mình sẽ giới thiệu ở bài sau. Bài viết tham khảo: 6 Ways to Unsubscribe from Observables in Angular

Tác giả
Cùng tác giả