在我的角+ RxJS应用程序中,我有一个有点复杂的管道结构:
remote-data.service.ts:
getAll(url): Observable<any[]> {
return this.http.get(url, this.options)
.pipe(map((result: any[]) => result));
}proxy.service.ts:
// localDataService use my LocalDataService
// remoteDataService use my RemoteDataService
getAll(model): Observable<any[]> {
if (model.use_localstorage) {
return this.localDataService.getAll(model)
.pipe(map((result: any[]) => result));
} else {
return this.remoteDataService.getAll(model.url)
.pipe(map((result: any[]) => result));
}
}helper.service.ts:
getAll(model): Observable<any[]> {
// do some general fancy things...
return this.proxyService.getAll(model)
.pipe(map((result: any) => result));
}
}然后在我的组件中
export class MyComponent {
helperService = new HelperService();
model = new MyModel();
getAll() {
this.helperService.getAll().subscribe((result: any[]) => {
// parse result
});
}
}正如您所看到的,我从远程数据服务、代理服务、助手服务和组件构建了一个管道。当然,这样做的原因是将每个函数从彼此之间分离开来,使我的服务更易于重用。
我的目标是避免内存泄漏。
问题是:如果我想把一个take(1) RxJS操作符放到我的管道中,它就足够把它放到管道的末尾,在.subscribe()之前,还是需要把它所有的服务和组件都放进去?
在这种情况下,避免内存泄漏的最佳实践是什么?
发布于 2020-05-31 10:25:40
那得看情况。pipe(take(1))确保您得到一个“可观察到的”值,这意味着它将发出一个值然后完成,并关闭订阅,因此不会出现内存泄漏。如果您的服务或函数本身只发出一个值,pipe(take(1))什么也不会做。
例如,如果您有REST调用,那么使用httpclient.get(...)它可能会有延迟。然后,您应该使用pipe(timeout(3000))或pipe(takeUntil(...))来确保没有子subscritpion活着,如果组件或任何东西被破坏了,那么在子存储中就不会有内存泄漏或逻辑的意外行为。即使使用pipe(take(1)),内存泄漏也可能存在,因为它只在发出一个值或错误之后才会完成。
因此,如果您有一个http.get(),而它有一个网络延迟。而且您将使用“管道(采取(1))”,它仍然会导致内存泄漏,因为它只等待一个值,并且订阅将在值到达时触发,即使调用中的组件已被销毁,或者您已导航到应用程序的另一个视图。
takeUntil(.)对于组件是有用的,如果它们被销毁,您可能会触发ngDestroy()中订阅的结束。
public isActive = new Subject();
public ngOnDestroy(): void {
this.isActive.next(false);
}
public fun():void{
this.fooService.getValue()
.pipe(takeUntil(this.isActive))
.subscribe( value => console.log(value));
}如果可观察/主题完成,则在发出最后一个值后不应该有内存泄漏。
您需要处理这些情况,如果您不确定,有一个“完整()”,或者如果它只发出一个值,但是延迟可能是有问题的。
内存泄漏只是次要的问题,甚至没有那么大。MOre的问题在于,当您不再想要订阅时,可能会触发订阅的逻辑。有时,您希望触发订阅中的逻辑(例如,通知告诉用户某件事情是成功的),即使用户已经离开了视图。所以要看情况了。
此外,如果您想要释放订阅,可以将所有订阅存储在单个订阅和取消订阅上。
public subs = new Subscription();
public ngOnDestroy(): void {
this.subs.unsubscribe();
}
public fun():void{
const bar: Subscription = this.fooService.getValue()
.subscribe( value => console.log(value));
this.subs.add(bar);
}发布于 2020-06-01 10:18:26
有一种常见的模式--在调用takeUntil(this.destroy$)之前,.subscribe应该是任何管道中的最新运算符。
class MyClass {
destroy$ = new Subject();
ngOnInit() {
this.stream$.pipe(
takeUntil(this.destroy$),
).subscribe(data => {
// some logic.
});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}有一个非常好的解释所有的问题,以及如何解决这些问题,以避免内存泄漏:https://blog.bitsrc.io/6-ways-to-unsubscribe-from-observables-in-angular-ab912819a78f
https://stackoverflow.com/questions/62114244
复制相似问题