使用 Angular,我有一个在组件中提供的服务。该服务具有一个可观察对象,组件已订阅此可观察对象。我原本以为不需要取消订阅该订阅/可观察对象,因为服务应随组件一起销毁,因此也应销毁可观察对象。然而,快速测试显示可观察对象仍然存在。
我的视线之外发生了什么?可观察对象是否在服务之外运行?或者当提供服务的组件被销毁时,服务实际上并没有被销毁?
我的视线之外发生了什么?可观察对象是否在服务之外运行?或者当提供服务的组件被销毁时,服务实际上并没有被销毁?
data$ = this.testService.testObservable();
并在视图中
<ng-container *ngIf="data$ | async as data">
{{ data | json }}
</ng-container>
2:取消订阅
this.subscription = this.testService.testObservable().subscribe(data => console.log(data));
ngOnDestroy() {
if (this.subscription) {
this.subscription.unsubscribe();
}
}
3: takeUntil
finalise = new Subject<void>();
this.subscription = this.testService.testObservable().pipe(takeUntil(this.finalise)).subscribe(data => console.log(data));
ngOnDestroy() {
this.finalise.next();
this.finalise.complete();
}
使用 takeUntil 处理你的情况。你需要创建/初始化一个主题,该主题将在组件销毁时完成。
private unsubscribe: Subject<void> = new Subject<void>();
this.testService.testObservable().pipe(takeUntil(this.unsubscribe))
.subscribe(data => console.log(data));
在组件销毁时完成订阅
使用一个主题和 takeUntil,您可以在 ngOnDestory 中一次性取消订阅多个可观察对象。
public ngOnDestroy(): void {
this.unsubscribe.next();
this.unsubscribe.complete();
}
// RxJS v6+
import { interval, timer } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
//emit value every 1s
const source = interval(1000);
//after 5 seconds, emit value
const timer$ = timer(5000);
//when timer emits after 5s, complete source
const example = source.pipe(takeUntil(timer$));
//output: 0,1,2,3
const subscribe = example.subscribe(val => console.log(val));
首先要注意的是,Angular服务是单例并且不会被销毁。
其次,您的可观察对象是在组件中订阅而不是在服务中订阅。 最后回答您的问题,
当组件被销毁时,订阅不会被销毁。 您需要手动取消订阅。 有几种方法可以做到这一点,最简单的方法是
- 不要订阅,而是在模板中使用Async管道。
根据yurzui的评论,我得出以下结论:
尽管服务已被销毁(因为它是在被销毁的组件中提供的),但可观察对象和订阅仍然在服务和组件之外继续工作。我假设这些不会在某个时刻被收集,因此我明确地清理它们。
我的问题不是如何取消订阅可观察对象,但无论如何,我认为分享我实际解决方案来管理我预期将被销毁的订阅是有用的。我在服务上创建了一个destroy()
函数,父组件在ngOnDestroy
周期中调用该函数。在此函数中,我从服务中的所有无限可观察对象发出完成信号。这样可以避免我在所有子组件中重复自己并取消订阅。
在我的服务中:
private subject = new BehaviorSubject<string>(null);
public testObservable(): Observable<string> {
// ...
this.subject.next('result');
return this.subject.asObservable();
}
destroy() {
this.subject.complete();
}
ngOnInit() {
this.testService.testObservable().subscribe(data => console.log(data));
}
ngOnDestroy() {
this.testService.destroy();
}
我已经包含了一个可工作的 StackBlitz,以防我的解决方案有些不确定:https://stackblitz.com/edit/destroyservice。我喜欢它的原因是我可以用3行代码取消订阅6个订阅,并且无需在任何子组件中包含 ngOnDestroy。
In my component
...providers: ...
。 - yurzui