![](/img/trans.png)
[英]Do you need to unsubscribe from a subscription to router params in Angular?
[英]Angular observables - Do I need unsubscribe if no subscription?
我正在使用最新的 angular 8 並且對 observables 的概念不熟悉。 我有一個問題,如果我直接調用一個可觀察對象而不將其應用於訂閱變量,我還需要取消訂閱嗎? 以下是我想知道是否需要退訂的場景? 提前謝謝了
場景 1 - 從組件調用 httpService:
Service - httpService
getContactsHttp(){
let headers: any = new HttpHeaders(this.authService.getHeadersClient());
return this.httpClient.get('/contacts', {headers: headers})
.pipe(timeout(this.authService.getTimeoutLimit('normal')));
}
Component - Calling getContactsHttp and sorting response
getContacts() {
this.httpService.getContactsHttp().subscribe((data:any[])=>{
this.records = this.sortData(data)
})
}
場景 2 - 在組件中訂閱的 observable
contacts$: new Subject<any[]>;
ngOnInit() {
this.getContacts();
this.contacts$.subscribe((data:any[])=>{
this.records = this.sortData(data);
})
}
getContacts() {
this.httpService.getContactsHttp().subscribe((data:ContactSearch[])=>{
this.contacts$.next(data);
})
}
服務 - httpService
getContactsHttp(){
let headers: any = new HttpHeaders(this.authService.getHeadersClient());
return this.httpClient.get('/contacts', {headers: headers})
.pipe(timeout(this.authService.getTimeoutLimit('normal')));
}
簡短的回答,是的,您仍然取消訂閱組件中的 observables 以 避免訂閱泄漏。 我首選的方法之一是使用takeUntil()運算符。
這就是您可以在組件中使用它的方式。
private unsubscribe: Subject<void> = new Subject();
ngOnDestroy() {
this.unsubscribe.next();
this.unsubscribe.complete();
}
getContacts() {
this.httpService.getContactsHttp()
.pipe(
takeUntil(this.unsubscribe),
).subscribe((data:ContactSearch[])=>{
this.contacts$.next(data);
});
}
正如Brian Love所解釋的,
- 首先,我們導入 takeUntil() 運算符以及 Subject class。
- 接下來,我們定義一個名為 unsubscribe 的私有實例屬性,它是一個 Subject。
- 我們還創建了一個 Subject 的新實例,將泛型類型定義為 void。 在調用 subscribe() 之前,我們在 pipe() 方法中使用 takeUntil() 運算符,提供 unsubscribe observable。
- 在 ngOnDestroy() 生命周期方法中,我們發出一個 next() 通知,然后完成() unsubscribe observable。 訂閱現已完成,當在組件的生命周期中調用 ngOnDestroy() 方法時,我們立即取消訂閱。
1)一般情況下,直接撥打http電話時不需要退訂。 即使組件被銷毀,銷毀后訂閱完成的開銷也是微不足道的。 如果快速切換組件,您需要在此處取消訂閱。 取消訂閱也會取消 http 請求,因此如果需要,請取消訂閱。
取消訂閱不會造成任何傷害。 如果您不確定,請始終退訂。
2)當您訂閱一個在您的組件被銷毀時未完成的可觀察對象時,您確實需要取消訂閱。 否則,這將導致 memory(和性能)泄漏。 因為 observable 本身持有對訂閱的引用,並且訂閱持有對組件的引用,所以組件永遠不會從 memory 中清除,並且訂閱中描述的操作將一直運行直到 observable 完成,在您的情況下永遠不會. 這將發生在您的組件的每個實例上。
我將分享兩個關於簡化退訂負擔的流行選項。 擴展 @amanagg1204 答案,您可以創建一個基礎組件,您可以從中擴展所有未來的組件。 您可以在其中包含自定義運算符。 這樣做有一個缺點 - 如果您需要在組件中使用ngOnDestroy
,則始終必須調用super.ngOnDestroy()
。
import { OnDestroy } from "@angular/core";
import { Subject, MonotypeOperatorFunction } from "rxjs";
import { takeUntil } from "rxjs/operators";
export abstract class UnsubscribeComponent implements OnDestroy {
protected destroyed$: Subject<void> = new Subject();
ngOnDestroy(): void {
this.destroyed$.next();
this.destroyed$.complete();
}
takeUntilDestroyed<T>(): MonoTypeOperatorFunction<T> {
return takeUntil(this.destroyed$);
}
}
export class Component extends UnsubscribeComponent {
ngOnInit() {
this.contacts$.pipe(
this.takeUntilDestroyed(),
).subscribe((data:any[])=>{
this.records = this.sortData(data);
});
}
// WARNING - if you declare your ngOnDestroy in the component
ngOnDestroy() {
// DO NOT FORGET to call this
super.ngOnDestroy();
doYourStuff();
}
}
其他選項(我的首選)是沒有父抽象 class (盡管也可以這樣實現),而是使用名為subsink
的實用程序( npm i subsink --save
)
import { SubSink } from 'subsink';
export class SampleComponent implements OnInit, OnDestroy {
private subs = new SubSink();
ngOnInit(): void {
// Just put it into sink.
this.subs.sink = this.contacts$.subscribe((data:any[])=>{
this.records = this.sortData(data);
});
// call repeatedly
this.subs.sink = this.otherService$.subscribe((data:any[])=>{
this.things = this.sortData(data);
});
}
ngOnDestroy(): void {
// this will unsubscribe all
this.subs.unsubscribe();
}
}
不會。HttpClient 返回一個冷的 observable,它在第一個訂閱者加入時觸發一次,並在 web 服務調用返回或錯誤時完成。
是的,總是退訂。 您有多種退訂方式,具體如下:
- 使用takeUntil()
- take(1)
- ngOnDestroy()
unsubscribe()
)
- 使用async
pipe
是的,httpClient 返回一個冷的 observable,但是這個問題將解釋你為什么仍然應該unsubscribe
。 (看第二個得票最高的答案)
是否有必要取消訂閱由 Http 方法創建的 observables?
https://blog.angularindepth.com/why-you-have-to-unsubscribe-from-observable-92502d5639d0
旁注:
1) 切勿訂閱服務。 我們處於 Angular 世界中,我們需要以一種被動的方式思考,在服務中購買訂閱會阻止您使用該 observable,以防您想將其與其他東西結合使用。
2) 在使用 observables 時開始使用聲明式方法。
3)停止使用any
,這不是一個好習慣。 使用類和接口,這樣您的代碼將更具可讀性。
聲明式方法的好處: -利用 RxJs 可觀察對象和操作符的強大功能 -有效組合流 -輕松共享可觀察對象 -輕松響應用戶操作
您可能想知道聲明性方法是什么樣的?
您將這樣做,而不是返回 observables 的方法。
服務.TS
yourObservableName$ = this.httpClient.get('/contacts', {headers: headers})
.pipe(timeout(this.authService.getTimeoutLimit('normal')));
組件.TS
this.httpService.yourObservableName$.subscribe(...)
正如許多人已經指出的那樣,http 返回一個 Cold Observable,但您仍然應該取消訂閱 observable。 我會建議一種更好的方式來管理退訂,這樣您就不必每次都手動添加 ngOnDestroy() 生命周期掛鈎。 我將首先創建一個取消訂閱組件,如下所示
import { OnDestroy } from "@angular/core";
import { Subject } from "rxjs";
export abstract class UnsubscribeComponent implements OnDestroy {
protected destroyed$: Subject<void> = new Subject();
ngOnDestroy(): void {
this.destroyed$.next();
this.destroyed$.complete();
}
}
然后在每個組件 class 聲明中擴展它(如果需要)
export class ABC extends UnsubscribeComponent
在構造函數中調用 super()
constructor(your dependencies) {
super()
}
最后使用您的訂閱,執行以下操作
this.obs$.pipe(takeUntil(this.destroyed$)).subscribe(() => {
// some logic here
})
另一件事是 takeUntil 應該是 pipe 中的最后一個運算符。 希望這對您有所幫助。
是的,取消訂閱 ngOnDestroy 生命周期方法中的所有訂閱是一個好習慣,您可以通過參考 class 級別變量中的每個訂閱然后手動取消訂閱來完成!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.