Angular 4+ ngOnDestroy()在使用中-销毁可观察到的


103

在有角度的应用程序中,我们ngOnDestroy()为组件/指令提供了生命周期挂钩,并使用该挂钩取消订阅可观察对象。

我想清除/破坏在@injectable()服务中创建的可观察性。我看到一些帖子说ngOnDestroy()可以在服务中使用。

但是,这是一种好的做法,并且是唯一的方法吗?何时调用它?有人请澄清。

Answers:


119

提供程序中提供了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是一个属于Foocomponent 的实例,因此可以在销毁它时Foo销毁它。

对于属于根注射器的提供程序,这将在应用程序销毁时发生,这有助于避免使用多个引导程序(即在测试中)导致内存泄漏。

当父注入者的提供者在子组件中被订阅时,它不会在销毁组件时被销毁,这是组件取消订阅组件的责任ngOnDestroy(如另一个答案所解释)。


不是class Service implements OnDestroy吗 如果在模块级别提供服务,那么在调用此方法时您会怎么想
Shumail

1
implements OnDestroy不会有任何影响,但可以添加以保持完整性。销毁模块时将调用它,例如appModule.destroy()。这对于多个应用程序初始化可能很有用。
Estus Flask

1
使用服务的每个组件都需要取消订阅吗?
阿里阿巴斯扎德

2
Plunker不适用于我,因此以下是该示例的StackBlitz版本:stackblitz.com/edit/angular-mggk9b
compuguru

1
我很难理解这一点。但是这个讨论帮助我理解了本地服务和全局服务之间的区别:stackoverflow.com/questions/50056446 / ...我认为是否必须“清理”取决于您的服务范围。
茉莉

25

在您的服务中创建一个变量

subscriptions: Subscriptions[]=[];

将每个订阅推送为

this.subscriptions.push(...)

写一个 dispose()方法

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

在ngOnDestroy期间从组件调用此方法

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

谢谢您的回复。我们是否知道何时调用此ngOnDestroy。?
mperle

是的,它说在清除指令或组件之前进行了一次清理调用。但我只想了解它是否也适用于服务?
mperle

卸载模块后,不会清除任何服务
-Aravind

2
生命周期挂钩不适用于@injectables
Aravind

@Aravind我不知道他们被介绍时,但他们
Estus Flask,

11

我更喜欢takeUntil(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我应该何时退订`Subscription`。



2

使用令牌时的警告

在尝试使我的应用程序尽可能模块化时,我经常使用提供者令牌为组件提供服务。看来这些ngOnDestroy方法没有得到称为:-(

例如。

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

在组件中具有提供者部分:

 {
     provide: PAYMENTPANEL_SERVICE,
     useExisting: ShopPaymentPanelService
 }

处置组件时,My ShopPaymentPanelService没有ngOnDestroy调用其方法。我只是很难找到答案!

一种解决方法是与结合提供服务useExisting

[
   ShopPaymentPanelService,

   {
       provide: PAYMENTPANEL_SERVICE,
       useExisting: ShopPaymentPanelService
   }
]

当我这样做时,ngOnDispose被称为预期。

不知道这是否是一个错误,但非常意外。


很好的提示!我想知道为什么在我的情况下它不起作用(我使用抽象类接口作为具体实现的标记)。
安德烈·辛尼森
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.