簡體   English   中英

Angular 4+ ngOnDestroy() 在服務中 - 銷毀 observable

[英]Angular 4+ ngOnDestroy() in service - destroy observable

在一個 angular 應用程序中,我們有一個組件/指令的ngOnDestroy()生命周期鈎子,我們使用這個鈎子來取消訂閱可觀察對象。

我想清除/銷毀在@injectable()服務中創建的可觀察對象。 我看到一些帖子說ngOnDestroy()也可以在服務中使用。

但是,這是一種很好的做法嗎?唯一的方法是什么時候調用它? 有人請澄清。

OnDestroy生命周期鈎子在提供者中可用。 根據文檔:

當指令、管道或服務被銷毀時調用的生命周期鈎子。

這是一個例子

@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)
  }
}

注意上面的代碼中Service是一個屬於Foo組件的實例,所以當Foo銷毀的時候可以銷毀它。

對於屬於根注入器的提供程序,這將在應用程序銷毀時發生,這有助於避免多個引導程序(即在測試中)的內存泄漏。

當來自父注入器的提供者在子組件中訂閱時,它不會在組件銷毀時被銷毀,這是組件有責任在組件ngOnDestroy取消訂閱(正如另一個答案所解釋的)。

在您的服務中創建一個變量

subscriptions: Subscriptions[]=[];

將您的每個訂閱推送到數組

this.subscriptions.push(...)

編寫一個dispose()方法

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

在 ngOnDestroy 期間從您的組件調用此方法

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

我更喜歡這種由 pipable 操作符啟用的 takeUntil takeUntil(onDestroy$)模式。 我喜歡這種模式更簡潔、更干凈,它清楚地傳達了在執行OnDestroy生命周期鈎子時OnDestroy訂閱的意圖。

這種模式適用於訂閱注入的可觀察對象的服務和組件。 下面的框架代碼應該為您提供了足夠的細節來將模式集成到您自己的服務中。 假設您正在導入一個名為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();
  }

何時/如何取消訂閱的主題在這里有廣泛的介紹: Angular/RxJs What should I unsubscribe from `Subscription`

只是為了澄清 - 您不需要銷毀Observables而只需要銷毀對它們進行的訂閱。

似乎其他人已經指出您現在也可以將ngOnDestroy與服務一起使用。 鏈接: https : //angular.io/api/core/OnDestroy

使用令牌時的注意事項

在嘗試使我的應用程序盡可能模塊化時,我經常使用提供者令牌為組件提供服務。 似乎這些沒有得到他們的ngOnDestroy方法調用:-(

例如。

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

使用組件中的 provider 部分:

 {
     provide: PAYMENTPANEL_SERVICE,
     useExisting: ShopPaymentPanelService
 }

在處理組件時,我的ShopPaymentPanelService沒有調用ngOnDestroy方法。 我剛剛發現這一點很困難!

解決方法是與useExisting一起提供服務。

[
   ShopPaymentPanelService,

   {
       provide: PAYMENTPANEL_SERVICE,
       useExisting: ShopPaymentPanelService
   }
]

當我這樣做時, ngOnDispose被按預期調用。

不確定這是否是一個錯誤,但非常出乎意料。

在您的服務中創建一個變量:

private subscriptions$ = new Subscription();

在構造函數(或 ngOnInit 生命周期鈎子)中將每個訂閱添加到 observable

ngOnInit() {
  this.subscriptions.add(...)
  this.subscriptions.add(...)
}

在銷毀時從您的組件調用此方法以取消訂閱所有訂閱和子訂閱。

ngOnDestroy(){
   this.subsriptions$.unsubscribe();
}

我推薦使用.pipe(take(1)).subscribe()。 避免設置持續訂閱。

TLDR;

import {DestroyRef} from "@angular/core";

// ...

constructor(destroyRef: DestroyRef) {
  fromEvent(window, 'resize')
    .pipe(takeUntilDestroyed(destroyRef))
    .subscribe(console.warn);
}

說明

DestroyRef注入目標構造型(module, service, directive, component, pipe) ,然后使用 RxJS takeUntilDestroyed運算符。

這是因為 Angular 的依賴注入 (DI) 和控制反轉 (IoC) 是分層的。 因此,每個構造型都有自己的注入器,通常繼承自父注入器。

因此,每個注入器管理器都有自己的生命周期並公開一個DestroyRef

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM