Angular 4+ ngOnDestroy () ในการให้บริการ - ทำลายที่สังเกตได้


106

ในแอปพลิเคชันเชิงมุมเรามีngOnDestroy()ตะขอเกี่ยวกับวงจรชีวิตสำหรับส่วนประกอบ / คำสั่งและเราใช้ตะขอนี้เพื่อยกเลิกการเป็นสมาชิกสิ่งที่สังเกตได้

ฉันต้องการล้าง / ทำลายที่สังเกตได้ซึ่งสร้างขึ้นใน@injectable()บริการ ฉันเห็นบางกระทู้บอกว่าngOnDestroy()สามารถใช้ในบริการได้เช่นกัน

แต่มันเป็นแนวทางปฏิบัติที่ดีและเป็นวิธีเดียวที่จะทำได้และเมื่อไหร่จะเรียก? ใครบางคนโปรดชี้แจง

คำตอบ:


124

OnDestroy lifecycle hook มีให้บริการในผู้ให้บริการ ตามเอกสาร:

Lifecycle hook ที่เรียกเมื่อคำสั่งท่อหรือบริการถูกทำลาย

นี่คือตัวอย่าง :

@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ถูกทำลาย

สำหรับผู้ให้บริการที่เป็นสมาชิกของ root injector สิ่งนี้จะเกิดขึ้นในการทำลายแอปพลิเคชันสิ่งนี้มีประโยชน์ในการหลีกเลี่ยงการรั่วไหลของหน่วยความจำด้วย bootstrap หลายตัวเช่นในการทดสอบ

เมื่อผู้ให้บริการจาก parent injector สมัครสมาชิกในองค์ประกอบย่อยจะไม่ถูกทำลายจากการทำลายส่วนประกอบนี่เป็นความรับผิดชอบขององค์ประกอบในการยกเลิกการสมัครสมาชิกในองค์ประกอบngOnDestroy(ตามที่อธิบายคำตอบอื่น)


ไม่class Service implements OnDestroy? และคุณคิดอย่างไรเมื่อสิ่งนี้ถูกเรียกว่าถ้าให้บริการในระดับโมดูล
Shumail

1
implements OnDestroyไม่ส่งผลกระทบใด ๆ แต่สามารถเพิ่มเพื่อความสมบูรณ์ appModule.destroy()มันจะถูกเรียกเมื่อโมดูลถูกทำลายเช่น สิ่งนี้อาจมีประโยชน์สำหรับการเริ่มต้นแอพหลายตัว
Estus Flask

1
การยกเลิกการสมัครจำเป็นสำหรับทุกองค์ประกอบที่ใช้บริการหรือไม่
Ali Abbaszade

2
Plunker ใช้งานไม่ได้สำหรับฉันดังนั้นนี่คือตัวอย่างเวอร์ชันStackBlitz
compuguru

1
ฉันมีปัญหาในการทำความเข้าใจเรื่องนี้ แต่การสนทนานี้ช่วยให้ฉันเข้าใจความแตกต่างระหว่างบริการในพื้นที่และทั่วโลก: stackoverflow.com/questions/50056446/…ไม่ว่าคุณจะต้อง "ล้างข้อมูล" หรือไม่นั้นขึ้นอยู่กับขอบเขตของบริการของคุณฉันคิดว่า
Jasmin

27

สร้างตัวแปรในบริการของคุณ

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$)รูปแบบนี้ที่เปิดใช้งานโดยตัวดำเนินการ pipable ฉันชอบที่รูปแบบนี้กระชับมากขึ้นสะอาดมากขึ้นและมันบ่งบอกถึงเจตนาที่จะฆ่าการสมัครสมาชิกอย่างชัดเจนเมื่อดำเนินการของ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 เมื่อใดที่ฉันควรยกเลิกการสมัครจาก `การสมัครสมาชิก '


5

เพียงเพื่อชี้แจง - คุณไม่จำเป็นต้องทำลายObservablesแต่เฉพาะการสมัครสมาชิกที่สร้างขึ้นกับพวกเขา

ดูเหมือนว่าคนอื่น ๆ ได้ชี้ให้เห็นว่าคุณสามารถใช้ngOnDestroyกับบริการได้แล้ว ลิงก์: https://angular.io/api/core/OnDestroy


1
คุณช่วยอธิบายเพิ่มเติมได้ไหม
Aravind

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ก็เรียกได้ว่าเป็นไปตามคาด

ไม่แน่ใจว่าเป็นบั๊กหรือไม่ แต่คาดไม่ถึง


คำใบ้สุดยอด! ฉันสงสัยว่าทำไมมันถึงใช้ไม่ได้ในกรณีของฉัน (ฉันใช้อินเทอร์เฟซคลาสนามธรรมเป็นโทเค็นสำหรับการนำไปใช้อย่างเป็นรูปธรรม)
Andrei Sinitson
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.