服务中的Angular 4+ ngOnDestroy() - 破坏可观察的

时间:2017-08-26 19:27:59

标签: angular rxjs observable angular-services

在一个角度应用程序中,我们有一个组件/指令的ngOnDestroy()生命周期钩子,我们使用这个钩子来取消订阅observables。

我想清除在@injectable()服务中创建的/ destory observable。 我看到一些帖子说ngOnDestroy()也可以在服务中使用。

但是,这是一个很好的做法,也是唯一的方法吗?什么时候会被调用? 有人请澄清。

6 个答案:

答案 0 :(得分:55)

提供程序中提供了

OnDestroy生命周期钩子。 根据文件:

  

销毁指令,管道或服务时调用的生命周期钩子。

这是example

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

@Component({
  selector: 'foo',
  template: `foo`,
  providers: [Service]
})
export class Foo {
  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中取消订阅的责任(另一个答案解释)

答案 1 :(得分:18)

在您的服务中创建变量

subscriptions: Subscriptions[]=[];

将每个订阅推送到数组

this.subscriptions.push(...)

编写dispose()方法

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

在ngOnDestroy

期间从您的组件调用此方法
ngOnDestroy(){
   this.service.dispose();
 }

答案 2 :(得分:5)

只是为了澄清 - 您不需要销毁Observables,只需要销毁订阅。

似乎其他人已经指出您现在也可以将ngOnDestroy用于服务。链接:https://angular.io/api/core/OnDestroy

答案 3 :(得分:3)

我更喜欢由可插值运算符启用的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 When should I unsubscribe from `Subscription`

答案 4 :(得分:1)

使用令牌时的注意事项

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

ngOnDestroy方法

例如

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

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

 {
     provide: PAYMENTPANEL_SERVICE,
     useExisting: ShopPaymentPanelService
 }

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

一种解决方法是与useExisting一起提供服务。

[
   ShopPaymentPanelService,

   {
       provide: PAYMENTPANEL_SERVICE,
       useExisting: ShopPaymentPanelService
   }
]

执行此操作时,ngOnDispose的调用符合预期。

不确定这是不是bug,但是非常意外。

答案 5 :(得分:0)

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

private subscriptions$ = new Subscription();

在构造函数(或 ngOnInit 生命周期钩子)中将每个订阅添加到 observable

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

在销毁时从您的组件调用此方法以取消订阅所有订阅和子订阅。

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