Angular 4+ ngOnDestroy () hizmette - gözlemlenebilir olanı yok et


106

Açısal bir uygulamada ngOnDestroy(), bir bileşen / yönerge için yaşam döngüsü kancasına sahibiz ve bu kancayı gözlemlenebilirlerin aboneliğinden çıkmak için kullanıyoruz.

Bir @injectable()hizmette yaratılan net / arzu edilen gözlemlenebilir istiyorum . Bunun ngOnDestroy()bir serviste de kullanılabileceğini söyleyen bazı yazılar gördüm .

Ancak, bu iyi bir uygulama mı ve bunu yapmanın tek yolu mu ve ne zaman çağrılacak? birisi lütfen açıklığa kavuştursun.

Yanıtlar:


124

OnDestroy yaşam döngüsü kancası sağlayıcılarda mevcuttur. Dokümanlara göre:

Bir yönerge, boru veya hizmet yok edildiğinde çağrılan yaşam döngüsü kancası.

İşte bir örnek :

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

Yukarıdaki kodda Service, Foobileşene ait bir örnek olduğuna dikkat edin , bu nedenle yok edildiğinde Fooyok edilebilir.

Kök enjektöre ait sağlayıcılar için bu, uygulama yok edildiğinde gerçekleşir, bu, birden çok önyükleme ile bellek sızıntılarını, yani testlerde önlemek için yararlıdır.

Üst enjektörden bir sağlayıcı alt bileşene abone olduğunda, bileşen yok edildiğinde yok edilmeyecektir, bu bileşenin aboneliğini iptal etme sorumluluğudur ngOnDestroy(başka bir yanıtın açıkladığı gibi).


Hayır class Service implements OnDestroymı? Ve modül düzeyinde servis sağlandıysa bu çağrıldığında ne düşünüyorsunuz
Shumail

1
implements OnDestroyhiçbir şeyi etkilemez ancak eksiksiz olması için eklenebilir. Gibi bir modül yok edildiğinde çağrılacaktır appModule.destroy(). Bu, birden çok uygulama başlatma için yararlı olabilir.
Estus Flask

1
Hizmetleri kullanan her bileşen için abonelikten çıkmak gerekli mi?
Ali Abbaszade

2
Plunker benim için çalışmıyordu, işte örneğin bir StackBlitz sürümü: stackblitz.com/edit/angular-mggk9b
compuguru

1
Bunu anlamakta biraz zorlandım. Ancak bu tartışma yerel ve küresel hizmetler arasındaki farkı anlamama yardımcı oldu: stackoverflow.com/questions/50056446/… "Temizlemeniz" gerekip gerekmediği, hizmetinizin kapsamına bağlıdır, sanırım.
Jasmin

27

Hizmetinizde bir değişken oluşturun

subscriptions: Subscriptions[]=[];

Her abonenizi diziye şu şekilde itin:

this.subscriptions.push(...)

Bir dispose()yöntem yazın

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

NgOnDestroy sırasında bileşeninizden bu yöntemi çağırın

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

Cevabın için teşekkürler. Bu ngOnDestroy'un ne zaman çağrılacağına dair bir fikrimiz var mı? ?
mperle

evet, direktif veya bileşen yok edilmeden önce bir temizleme çağrısı olduğunu söylüyor. ancak bunun hizmet için de geçerli olup olmadığını anlamak istiyorum.
mperle

Modül kaldırıldığında hiçbir hizmet temizlenmeyecek
Aravind

2
kullanım ömrü kancaları@injectables
Aravind

@Aravind Ne zaman tanıtıldıklarından emin değilim ama onlar .
Estus Flask

11

takeUntil(onDestroy$)Borç verilebilir operatörlerin etkinleştirdiği bu modeli tercih ederim . Bu modelin daha özlü, daha temiz olmasını seviyorum ve OnDestroyyaşam döngüsü kancasının yürütülmesi üzerine bir aboneliği sonlandırma niyetini açıkça iletiyor .

Bu model servisler için olduğu kadar enjekte edilen gözlemlenebilirlere abone olan bileşenler için de işe yarar. Aşağıdaki iskelet kodu, kalıbı kendi hizmetinize entegre etmek için size yeterli ayrıntı vermelidir. InjectedService... adlı bir hizmeti içe aktardığınızı hayal edin ...

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();
  }

Abonelikten ne zaman / nasıl çıkılacağı burada kapsamlı bir şekilde ele alınmaktadır : Angular / RxJs "Abonelik" üyeliğinden ne zaman çıkmalıyım?


5

Sadece açıklığa kavuşturmak için - yok etmeniz gerekmez, Observablesyalnızca onlara yapılan abonelikleri kaldırmanız gerekir.

Görünüşe göre diğerleri artık ngOnDestroyhizmetlerle de kullanabileceğinizi belirtmişler . Bağlantı: https://angular.io/api/core/OnDestroy


1
Lütfen biraz daha detaylandırır mısınız
Aravind

2

Jeton kullanılıyorsa dikkat

Uygulamamı olabildiğince modüler yapmaya çalışırken, bir bileşene hizmet sağlamak için genellikle sağlayıcı belirteçlerini kullanacağım. Görünüşe göre bunlar, ngOnDestroyyöntemlerini :-(

Örneğin.

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

Bir bileşendeki sağlayıcı bölümü ile:

 {
     provide: PAYMENTPANEL_SERVICE,
     useExisting: ShopPaymentPanelService
 }

Bileşen atıldığında benim yönteminin çağrılan yöntemi ShopPaymentPanelServiceYOKTUR ngOnDestroy. Bunu zor yoldan öğrendim!

Geçici çözüm, hizmeti ile birlikte sağlamaktır useExisting.

[
   ShopPaymentPanelService,

   {
       provide: PAYMENTPANEL_SERVICE,
       useExisting: ShopPaymentPanelService
   }
]

Bunu yaptığımda ngOnDisposebeklendiği gibi çağrıldı.

Bunun bir hata olup olmadığından emin değilim, ancak çok beklenmedik.


Harika bir ipucu! Benim durumumda neden çalışmadığını merak ediyordum (somut uygulama için bir simge olarak soyut sınıf arayüzünü kullanıyordum).
Andrei Sinitson
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.