防止 Angular 2 中的内存泄漏?

Posted

技术标签:

【中文标题】防止 Angular 2 中的内存泄漏?【英文标题】:Prevent memory leaks in Angular 2? 【发布时间】:2016-03-31 10:23:22 【问题描述】:

在 Angular 2 中,我应该注意内存管理方面的任何特定缺陷吗?

为了避免可能的泄漏,管理组件状态的最佳做法是什么?

具体来说,我在ngOnDestroy 方法中看到了一些人unsubscribing from HTTP observables。我应该一直这样做吗?

在 Angular 1.X 中,我知道当 $scope 被销毁时,它上面的所有侦听器也会自动被销毁。 Angular 2 组件中的 observables 呢?

@Component(
  selector: 'library',
  template: `
    <tr *ngFor="#book of books | async">
        <td> book.title.text </td>
        <td> book.author.text </td>
    </tr>
  `
)
export class Library 
    books: Observable<any>;

    constructor(private backend: Backend) 
        this.books = this.backend.get('/texts'); // <-- does it get destroyed
                                                 //     with the component?
    
;

【问题讨论】:

别忘了取消订阅 ngOnDestroy 中的 Observable 在您的情况下,取消订阅 ngOnDestroy 中的 Observable 是不必要的,Async 管道会为您处理所有这些。那将是一个好习惯,而不是自己订阅,让管道为你做所有事情。 @EricMartinez,谢谢!我会接受这个答案(特别是如果您提供证明链接)。 这能回答你的问题吗? Is it necessary to unsubscribe from observables created by Http methods? 【参考方案1】:

根据@katspaugh 的要求

在您的特定情况下,无需手动取消订阅,因为这是异步管道的工作。

检查 AsyncPipe 的 source code。为简洁起见,我发布了相关代码

class AsyncPipe implements PipeTransform, OnDestroy 
    // ...
    ngOnDestroy(): void 
        if (isPresent(this._subscription)) 
          this._dispose();
        
    

如您所见,Async 管道实现了 OnDestroy,当它被销毁时,它会检查是否有订阅并将其删除。

在这种特定情况下,您将重新发明***(抱歉重复我自己)。这并不意味着您不能/不应该在您引用的任何其他情况下取消订阅。在这种情况下,用户在组件之间传递 Observable 以进行通信,因此最好手动取消订阅。

我不知道框架是否可以检测到任何活动订阅并在组件被销毁时自动取消订阅,这当然需要更多调查。

我希望这能澄清一点关于异步管道的信息。

【讨论】:

嘿@katspaugh 我从 Rob 那里得到了答复,我想你可能会对它感兴趣,在这个 comment 中查看它 也看看这个hangout talk(27:40 分),它并没有深入探讨这个主题,但我很好奇,因为你的问题并发现了那个视频。 谢谢,有趣!所以 Rob 基本上说你不需要取消订阅包含单个值的 observables(HTTP 请求就是其中的一个例子)。【参考方案2】:

您不必像在 http.get() 之后那样取消订阅标准订阅。 但是您必须取消订阅自定义主题的订阅。如果您有某个组件并且在其中订阅了服务中的某个主题,那么每次您显示该组件时,都会将新订阅添加到主题中。

请查看:Good solution to make your components 'clean'

我个人的方法——我所有的组件都是从这个不错的类中扩展而来的:

import  OnDestroy, OnInit  from '@angular/core';
import  Subject  from 'rxjs/Subject';

/**
 * A component that cleans all subscriptions with oneself
 * https://***.com/questions/38008334/angular-rxjs-when-should-i-unsubscribe-from-subscription
 * @class NeatComponent
 */
export abstract class NeatComponent implements OnDestroy, OnInit 
// Add '.takeUntil(this.ngUnsubscribe)' before every '.subscrybe(...)'
// and this subscriptions will be cleaned up on component destroy.

  protected ngUnsubscribe: Subject<any> = new Subject();

  public ngOnDestroy() 
    this.ngUnsubscribe.next();
    this.ngUnsubscribe.complete();
  

  public ngOnInit()

我只是在每次订阅之前添加 super() 调用构造函数和 .takeUntil(this.ngUnsubscribe)

import  NeatComponent  from '../../types/neat.component';

@Component(
  selector: 'category-selector',
  templateUrl: './category-selector.component.pug'
)
export class CategorySelectorComponent extends NeatComponent 

  public constructor(
    private _shopService: ShopsService
  )  super(); 

  public ngOnInit() 
    this._shopService.categories.takeUntil(this.ngUnsubscribe)
      .subscribe((categories: any) => 
        // your code here
      )
  

【讨论】:

以上是关于防止 Angular 2 中的内存泄漏?的主要内容,如果未能解决你的问题,请参考以下文章

防止 WPF 中的内存泄漏

如何防止 JTextPane.setCaretPosition(int) 中的内存泄漏?

如何防止 node.js 中的内存泄漏?

如何减少/消除 Angular 应用程序中的内存泄漏

在 useEffect 挂钩中取消所有异步/等待任务以防止反应中的内存泄漏的正确方法是啥?

防止相关功能中的内存泄漏[关闭]