首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何避免角9中复杂RxJS管道的内存泄漏?

如何避免角9中复杂RxJS管道的内存泄漏?
EN

Stack Overflow用户
提问于 2020-05-31 09:38:30
回答 2查看 4.2K关注 0票数 4

在我的角+ RxJS应用程序中,我有一个有点复杂的管道结构:

remote-data.service.ts:

代码语言:javascript
复制
getAll(url): Observable<any[]> {
  return this.http.get(url, this.options)
    .pipe(map((result: any[]) => result));
}

proxy.service.ts:

代码语言:javascript
复制
// 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:

代码语言:javascript
复制
getAll(model): Observable<any[]> {
  // do some general fancy things...
  return this.proxyService.getAll(model)
      .pipe(map((result: any) => result));
  }
}

然后在我的组件

代码语言:javascript
复制
export class MyComponent {
  helperService = new HelperService();
  model = new MyModel();

  getAll() {
    this.helperService.getAll().subscribe((result: any[]) => {
      // parse result
    });
  }
}

正如您所看到的,我从远程数据服务、代理服务、助手服务和组件构建了一个管道。当然,这样做的原因是将每个函数从彼此之间分离开来,使我的服务更易于重用。

我的目标是避免内存泄漏。

问题是:如果我想把一个take(1) RxJS操作符放到我的管道中,它就足够把它放到管道的末尾,在.subscribe()之前,还是需要把它所有的服务和组件都放进去?

在这种情况下,避免内存泄漏的最佳实践是什么?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 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()中订阅的结束。

代码语言:javascript
复制
  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的问题在于,当您不再想要订阅时,可能会触发订阅的逻辑。有时,您希望触发订阅中的逻辑(例如,通知告诉用户某件事情是成功的),即使用户已经离开了视图。所以要看情况了。

此外,如果您想要释放订阅,可以将所有订阅存储在单个订阅和取消订阅上。

代码语言:javascript
复制
  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);
  }
票数 4
EN

Stack Overflow用户

发布于 2020-06-01 10:18:26

有一种常见的模式--在调用takeUntil(this.destroy$)之前,.subscribe应该是任何管道中的最新运算符。

代码语言:javascript
复制
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

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62114244

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档