net*_*djw 5 memory-leaks rxjs typescript angular
我的 Angular + RxJS 应用程序中有一点复杂的管道结构:
远程数据.service.ts:
getAll(url): Observable<any[]> {
return this.http.get(url, this.options)
.pipe(map((result: any[]) => result));
}
Run Code Online (Sandbox Code Playgroud)
代理.服务.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));
}
}
Run Code Online (Sandbox Code Playgroud)
助手.service.ts:
getAll(model): Observable<any[]> {
// do some general fancy things...
return this.proxyService.getAll(model)
.pipe(map((result: any) => result));
}
}
Run Code Online (Sandbox Code Playgroud)
然后在我的组件中:
export class MyComponent {
helperService = new HelperService();
model = new MyModel();
getAll() {
this.helperService.getAll().subscribe((result: any[]) => {
// parse result
});
}
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,我从远程数据服务、代理服务、帮助服务和组件构建了一个管道。当然,原因是为了将每个功能彼此分离,并使我的服务更具可重用性。
我的目标是避免内存泄漏。
问题是:如果我想将take(1)RxJS 运算符放入管道中,那么将其放入管道末尾就足够了,或者.subscribe()需要将其放入每个服务和组件之前吗?
在这种情况下避免内存泄漏的最佳实践是什么?
这取决于。pipe(take(1))确保您获得“可观察到的单个值”的含义,即它将发出一个值,然后完成并关闭订阅,因此不会出现内存泄漏。如果您的服务或函数本身仅发出单个值,pipe(take(1))则不会执行任何操作。
例如,如果您有 REST 调用,则httpclient.get(...)可能会有延迟。然后,您应该使用pipe(timeout(3000))或pipe(takeUntil(...))来确保订阅不存在,如果您的组件或任何内容被破坏,您不会出现内存泄漏或订阅内逻辑的意外行为。即使pipe(take(1))内存泄漏也可能存在,因为它只有在恰好发出一个值或错误后才会完成。
因此,如果您有一个http.get()并且它有网络延迟。而且您将使用“pipe(take(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));
}
Run Code Online (Sandbox Code Playgroud)
如果 Observable/Subject 完成,则在发出最后一个值后不应出现内存泄漏。
您需要处理这些情况,如果您不确定是否存在“complete()”,或者它是否只发出一个值,但延迟可能会出现问题。
顺便说一句,内存泄漏是次要问题,而且没有那么大。更成问题的是,当您不再想要时,您的订阅逻辑可能会被触发。有时,即使用户已经离开视图,您也希望触发订阅中的逻辑(例如告诉用户某件事成功的通知)。所以这取决于。
此外,您还可以将所有订阅存储在单个订阅中,如果您想处置它们,则可以取消订阅。
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);
}
Run Code Online (Sandbox Code Playgroud)