Angular 4+ ngOnDestroy () trong dịch vụ - hủy có thể quan sát được


103

Trong một ứng dụng góc cạnh, chúng ta có ngOnDestroy()móc vòng đời cho một thành phần / chỉ thị và chúng ta sử dụng móc này để hủy đăng ký các có thể quan sát.

Tôi muốn xóa / hủy có thể quan sát được được tạo trong một @injectable()dịch vụ. Tôi thấy một số bài đăng nói rằng nó ngOnDestroy()cũng có thể được sử dụng trong một dịch vụ.

Nhưng, đó có phải là một cách thực hành tốt và cách duy nhất để làm như vậy và Khi nào nó sẽ được gọi? ai đó xin vui lòng làm rõ.

Câu trả lời:


119

OnDestroy vòng đời hook có sẵn trong các nhà cung cấp. Theo tài liệu:

Móc vòng đời được gọi khi một chỉ thị, đường ống hoặc dịch vụ bị phá hủy.

Đây là một ví dụ :

@Injectable()
class Service implements OnDestroy {
  ngOnDestroy() {
    console.log('Service destroy')
  }
}

@Component({
  selector: 'foo',
  template: `foo`,
  providers: [Service]
})
export class Foo implements OnDestroy {
  constructor(service: Service) {}

  ngOnDestroy() {
    console.log('foo destroy')
  }
}

@Component({
  selector: 'my-app',
  template: `<foo *ngIf="isFoo"></foo>`,
})
export class App {
  isFoo = true;

  constructor() {
    setTimeout(() => {
        this.isFoo = false;
    }, 1000)
  }
}

Lưu ý rằng trong đoạn mã trên Servicelà một thể hiện thuộc về Foothành phần, vì vậy nó có thể bị hủy khi Foobị hủy.

Đối với các nhà cung cấp thuộc bộ cung cấp root, điều này sẽ xảy ra khi phá hủy ứng dụng, điều này rất hữu ích để tránh rò rỉ bộ nhớ với nhiều chuỗi khởi động, tức là trong các thử nghiệm.

Khi một nhà cung cấp từ bộ cung cấp gốc được đăng ký trong thành phần con, nó sẽ không bị hủy khi hủy thành phần, đây là trách nhiệm của thành phần để hủy đăng ký trong thành phần ngOnDestroy(như một câu trả lời khác giải thích).


Không class Service implements OnDestroy? Và bạn nghĩ gì khi điều này được gọi là nếu dịch vụ được cung cấp trên cấp module
Shumail

1
implements OnDestroykhông ảnh hưởng gì nhưng có thể được thêm vào cho hoàn chỉnh. Nó sẽ được gọi khi một mô-đun bị phá hủy, như appModule.destroy(). Điều này có thể hữu ích cho nhiều lần khởi chạy ứng dụng.
Estus Flask

1
Hủy đăng ký có cần thiết cho mọi thành phần sử dụng dịch vụ không?
Ali Abbaszade

2
Plunker không hoạt động với tôi, vì vậy đây là phiên bản StackBlitz của ví dụ: stackblitz.com/edit/angular-mggk9b
compuguru

1
Tôi đã gặp một số khó khăn để hiểu điều này. Nhưng cuộc thảo luận này đã giúp tôi hiểu sự khác biệt giữa dịch vụ cục bộ và dịch vụ toàn cầu: stackoverflow.com/questions/50056446/… Việc bạn có phải "dọn dẹp" hay không phụ thuộc vào phạm vi dịch vụ của bạn, tôi nghĩ.
Jasmin

25

Tạo một biến trong dịch vụ của bạn

subscriptions: Subscriptions[]=[];

Đẩy từng đăng ký của bạn vào mảng như

this.subscriptions.push(...)

Viết một dispose()phương pháp

dispose(){
this.subscriptions.forEach(subscription =>subscription.unsubscribe())

Gọi phương thức này từ thành phần của bạn trong ngOnDestroy

ngOnDestroy(){
   this.service.dispose();
 }

Cảm ơn bạn đã trả lời. Chúng tôi có bất kỳ ý tưởng khi nào ngOnDestroy này sẽ được gọi không. ?
mperle

vâng nó cho biết nó là một cuộc gọi dọn dẹp trước khi chỉ thị hoặc thành phần bị phá hủy. nhưng tôi chỉ muốn hiểu liệu nó có áp dụng cho cả dịch vụ không?
mperle

Không có dịch vụ nào sẽ bị xóa khi mô-đun được dỡ bỏ
Aravind

2
móc vòng đời không được áp dụng cho@injectables
Aravind

@Aravind Tôi không chắc khi nào chúng được giới thiệu nhưng chúng đã có .
Estus Flask

11

Tôi thích takeUntil(onDestroy$)mẫu này được kích hoạt bởi các toán tử có thể chuyển đổi. Tôi thích rằng mẫu này ngắn gọn hơn, rõ ràng hơn và nó truyền đạt rõ ràng ý định giết đăng ký khi thực hiện OnDestroymóc vòng đời.

Mẫu này hoạt động cho các dịch vụ cũng như các thành phần đăng ký vào các vật thể quan sát được đưa vào. Mã khung bên dưới sẽ cung cấp cho bạn đủ chi tiết để tích hợp mẫu vào dịch vụ của riêng bạn. Hãy tưởng tượng bạn đang nhập một dịch vụ có tên là InjectedService...

import { InjectedService } from 'where/it/lives';
import { Injectable, OnDestroy } from '@angular/core';
import { Observable } from 'rxjs/Rx';
import { takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs/Subject';

@Injectable()
export class MyService implements OnDestroy {

  private onDestroy$ = new Subject<boolean>();

  constructor(
    private injectedService: InjectedService
  ) {
    // Subscribe to service, and automatically unsubscribe upon `ngOnDestroy`
    this.injectedService.observableThing().pipe(
      takeUntil(this.onDestroy$)
    ).subscribe(latestTask => {
      if (latestTask) {
        this.initializeDraftAllocations();
      }
    });
  }

  ngOnDestroy() {
    this.onDestroy$.next(true);
    this.onDestroy$.complete();
  }

Chủ đề về thời điểm / cách hủy đăng ký được đề cập rộng rãi ở đây: Angular / RxJs Khi nào thì tôi nên hủy đăng ký khỏi `Đăng ký`


5

Chỉ cần làm rõ - bạn không cần phải hủy Observablesmà chỉ cần đăng ký cho họ.

Có vẻ như những người khác đã chỉ ra rằng bạn hiện cũng có thể sử dụng ngOnDestroyvới các dịch vụ. Liên kết: https://angular.io/api/core/OnDestroy


1
Bạn có thể vui lòng giải thích thêm về nó không
Aravind

2

Thận trọng nếu sử dụng mã thông báo

Để cố gắng làm cho ứng dụng của mình theo mô-đun càng tốt, tôi thường sử dụng mã thông báo của nhà cung cấp để cung cấp dịch vụ cho một thành phần. Có vẻ như chúng KHÔNG nhận được các ngOnDestroyphương thức của chúng được gọi là :-(

ví dụ.

export const PAYMENTPANEL_SERVICE = new InjectionToken<PaymentPanelService>('PAYMENTPANEL_SERVICE');

Với phần nhà cung cấp trong một thành phần:

 {
     provide: PAYMENTPANEL_SERVICE,
     useExisting: ShopPaymentPanelService
 }

My ShopPaymentPanelServiceKHÔNG có ngOnDestroyphương thức của nó được gọi khi thành phần được xử lý. Tôi chỉ tìm thấy điều này một cách khó khăn!

Một cách giải quyết là cung cấp dịch vụ kết hợp với useExisting.

[
   ShopPaymentPanelService,

   {
       provide: PAYMENTPANEL_SERVICE,
       useExisting: ShopPaymentPanelService
   }
]

Khi tôi làm điều này ngOnDisposeđược gọi là như mong đợi.

Không chắc đây có phải là lỗi hay không nhưng rất bất ngờ.


Gợi ý tuyệt vời! Tôi đã tự hỏi tại sao nó không hoạt động trong trường hợp của tôi (tôi đang sử dụng giao diện lớp trừu tượng làm mã thông báo để triển khai cụ thể).
Andrei Sinitson
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.