我使用的是最新的角度8,对可观察对象的概念不熟悉。如果我直接调用可观察对象而不将其应用于订阅变量,我还需要取消订阅吗?下面是我想知道是否需要取消订阅的场景?非常感谢
场景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-组件中的可观察到的脚本
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')));
}
简而言之,是的,您仍然取消订阅组件中的可观察对象以避免订阅泄漏。我更喜欢这样做的方法之一是使用带直到()运算符。
这就是您可以在组件中使用它的方式。
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);
});
}
正如布莱恩·洛夫所解释的,
1)通常,直接调用超文本传输协议调用时不需要取消订阅。即使组件被销毁,销毁后订阅完成的开销也不大。如果快速切换组件,您需要在此取消订阅。取消订阅也会取消超文本传输协议请求,所以如果需要,请取消订阅。
退订没有任何坏处。如果你不确定,总是退订。
2)当订阅一个在组件被销毁时未完成的可观察对象时,您确实需要取消订阅。否则这将导致内存(和性能)泄漏。因为可观察对象本身持有对订阅的引用,而订阅持有对组件的引用,所以组件永远不会从内存中清除,订阅中描述的操作将一直运行,直到可观察对象完成,在您的情况下,这永远不会发生。这将发生在您的组件的每个实例中。
我将分享两个简化退订负担的流行选项。扩展@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();
}
}
其他选择(我的首选)不是有一个父抽象类(尽管它也可以这样实现),而是使用一个名为subink
的实用程序(npm i subink--sav
)
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();
}
}
是的,始终取消订阅。您有多种取消订阅的方式,如下所示:
-使用带直到()
-取(1)
-在ngOnDestroy()
中取消订阅()
-使用async
管道
是的,httpClient返回一个冷可观察值,但这个问题将解释为什么您仍然应该取消订阅
。(看看投票最高的第二个答案)
是否有必要取消订阅由Http方法创建的可观察对象?
https://blog.angularindepth.com/why-you-have-to-unsubscribe-from-observable-92502d5639d0
在旁注:
1)永远不要在服务中订阅。我们在Angular世界中,我们需要以被动的方式思考,在服务中购买订阅会阻止你使用那个可观察的东西,以防你想把它和其他东西结合起来。
2)在使用可观察对象时开始使用声明性方法。
3)停止使用任何
,这不是好的做法。使用类和接口,这样你的代码会更具可读性。
声明式方法的好处:-利用RxJs可观察对象和运算符的强大功能-有效组合流-轻松共享可观察对象-随时对用户操作做出反应
你可能想知道声明式方法是什么样的?
您将执行此操作,而不是使用返回可观察对象的方法。
服务. TS
yourObservableName$ = this.httpClient.get('/contacts', {headers: headers})
.pipe(timeout(this.authService.getTimeoutLimit('normal')));
组件. TS
this.httpService.yourObservableName$.subscribe(...)