角度内存泄漏需要知道如何解决泄漏。

huangapple go评论69阅读模式
英文:

angular memory leak need to know how to solve leak

问题

我有一个代码正在泄漏,我需要知道为什么或者如何正确取消订阅。即使当我添加了一个包含所有对象的数组时,订阅仍然在泄漏。

import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { of } from 'rxjs';
import { delay, tap, mergeMap, repeat } from 'rxjs/operators';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {

  postId;

  callOmni = () => of(this.pollOmni()).pipe();
  display = response => {};
  poll = of({}).pipe(
    mergeMap(_ => this.callOmni()),
    tap(this.display),
    delay(10),
    repeat()
  );

  constructor(private http: HttpClient) { } 
  pollOmni() {      
    // 简单的带有 JSON 主体和响应类型<any>的 POST 请求
    this.http.post<any>('http://127.0.0.1:8084/api', { call: 'getinfo' }).subscribe(
      data => {
        this.postId = data;
        console.log(this.postId);
      },
      error => {
        console.log('出错', error)
      }
    );
  }

  ngOnInit() {      
    // 简单的带有 JSON 主体和响应类型<any>的 POST 请求
    this.poll.subscribe();
  }

}
英文:

I have a code that is leaking and I need to know why or how to unsubscibe correcly .
since even when I added an array that is all objects subscibed are being deleted it still leaks

import { Component, OnInit } from &#39;@angular/core&#39;;
import { HttpClient } from &#39;@angular/common/http&#39;;
import { of } from &#39;rxjs&#39;;
import { delay, tap, mergeMap, repeat } from &#39;rxjs/operators&#39;;

@Component({
  selector: &#39;app-root&#39;,
  templateUrl: &#39;./app.component.html&#39;,
  styleUrls: [&#39;./app.component.css&#39;]
})
export class AppComponent implements OnInit {

  postId;
  
  callOmni = () =&gt; of(this.pollOmni()).pipe();
  display = response =&gt; {};
  poll = of({}).pipe(
  mergeMap(_ =&gt; this.callOmni()),
  tap(this.display),
  delay(10),
  repeat()
);

  constructor(private http: HttpClient) { } 
  pollOmni() {      
    // Simple POST request with a JSON body and response type &lt;any&gt;
    this.http.post&lt;any&gt;(&#39;http://127.0.0.1:8084/api&#39;, { call: &#39;getinfo&#39; }).subscribe(
      data =&gt; {
        this.postId = data;
        console.log(this.postId);
        }),
        error =&gt; {
          console.log(&#39;oops&#39;, error)
        }
     
   
  }

  ngOnInit() {      
    // Simple POST request with a JSON body and response type &lt;any&gt;
   
    this.poll.subscribe();
  }

}

答案1

得分: 1

在你的代码中,似乎在pollOmni()方法内有一个订阅,而这个方法被多次调用。这可能会导致多个未取消订阅的活跃订阅,从而引发内存泄漏问题。

为了解决这个问题,你需要确保在不再需要时取消订阅。一种方法是将订阅存储在一个变量中,并在需要时进行取消订阅。

以下是实现必要更改的代码更新版本:

import { Component, OnInit, OnDestroy } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { of, Subject } from 'rxjs';
import { delay, tap, mergeMap, repeat, takeUntil } from 'rxjs/operators';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit, OnDestroy {
  postId;
  private ngUnsubscribe = new Subject<void>(); // 用于取消订阅的 Subject

  constructor(private http: HttpClient) { }

  callOmni = () => of(this.pollOmni()).pipe();

  display = response => {
    // 在这里添加显示逻辑
  };

  poll = of({}).pipe(
    mergeMap(_ => this.callOmni()),
    tap(this.display),
    delay(10),
    repeat(),
    takeUntil(this.ngUnsubscribe) // 当 ngUnsubscribe 发出信号时取消订阅
  );

  pollOmni() {
    return this.http.post<any>('http://127.0.0.1:8084/api', { call: 'getinfo' });
  }

  ngOnInit() {
    this.poll.subscribe();
  }

  ngOnDestroy() {
    this.ngUnsubscribe.next(); // 发出信号以取消正在进行的订阅
    this.ngUnsubscribe.complete(); // 完成 Subject
  }
}

请注意,我只翻译了代码部分,没有包含其他内容。

英文:

In your code, it seems that you have a subscription inside the pollOmni() method, which is called multiple times. This can lead to multiple active subscriptions that are not unsubscribed, causing a memory leak.

To fix this, you need to make sure that you unsubscribe from the subscription when it's no longer needed. One way to achieve this is by storing the subscription in a variable and unsubscribing from it when necessary.

Here's an updated version of your code that implements the necessary changes:

import { Component, OnInit, OnDestroy } from &#39;@angular/core&#39;;
import { HttpClient } from &#39;@angular/common/http&#39;;
import { of, Subject } from &#39;rxjs&#39;;
import { delay, tap, mergeMap, repeat, takeUntil } from &#39;rxjs/operators&#39;;

@Component({
  selector: &#39;app-root&#39;,
  templateUrl: &#39;./app.component.html&#39;,
  styleUrls: [&#39;./app.component.css&#39;]
})
export class AppComponent implements OnInit, OnDestroy {
  postId;
  private ngUnsubscribe = new Subject&lt;void&gt;(); // Subject for unsubscribing

  constructor(private http: HttpClient) { }

  callOmni = () =&gt; of(this.pollOmni()).pipe();

  display = response =&gt; {
    // Display logic here
  };

  poll = of({}).pipe(
    mergeMap(_ =&gt; this.callOmni()),
    tap(this.display),
    delay(10),
    repeat(),
    takeUntil(this.ngUnsubscribe) // Unsubscribe when ngUnsubscribe emits
  );

  pollOmni() {
    return this.http.post&lt;any&gt;(&#39;http://127.0.0.1:8084/api&#39;, { call: &#39;getinfo&#39; });
  }

  ngOnInit() {
    this.poll.subscribe();
  }

  ngOnDestroy() {
    this.ngUnsubscribe.next(); // Emit value to unsubscribe from ongoing subscriptions
    this.ngUnsubscribe.complete(); // Complete the subject
  }
}

答案2

得分: 0

export class AppComponent implements OnInit, OnDestroy {
...

ngOnDestroy(): void {
    this.poll.unsubscribe();
}

}

英文:

Something like that:

export class AppComponent implements OnInit, OnDestroy {    
  ...

  ngOnDestroy(): void {
    this.poll.unsubscribe();
  }
}

答案3

得分: 0

在你的代码中实现Angular中的OnDestroy生命周期钩子,并在ngOnDestroy方法中进行unsubscribe操作,如下所示:

import { Component, OnInit, OnDestroy } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { of } from 'rxjs';
import { delay, tap, mergeMap, repeat, takeUntil } from 'rxjs/operators';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit, OnDestroy {

  postId;
  private unsubscribe = new Subject<void>();
  callOmni = () => of(this.pollOmni()).pipe();
  display = response => {};
  poll = of({}).pipe(
    mergeMap(_ => this.callOmni()),
    tap(this.display),
    delay(10),
    repeat(),
    takeUntil(this.unsubscribe)
  );

  constructor(private http: HttpClient) { } 
  pollOmni() {      
    this.http.post<any>('http://127.0.0.1:8084/api', { call: 'getinfo' }).subscribe(
      data => {
        this.postId = data;
        console.log(this.postId);
      },
      error => {
        console.log('oops', error);
      }
    );
  }

  ngOnInit() {      
    this.poll.subscribe();
  }

  ngOnDestroy(): void {
    this.unsubscribe.next(); 
    this.unsubscribe.complete();
  }
}

如果上述方法对你不起作用,我建议在Angular中实现模板机制,使用Angular Async Pipe。请参考以下示例来使用pipes在Angular中实现模板机制:

@Component({
  selector: 'app-stock',
  template: `
    <div *ngIf="stocks$ | async as stocks">
      <ul>
        <li *ngFor="let stock of stocks">
          {{ stock.symbol }}
        </li>
      </ul>
    </div>
  `,
  styleUrls: ['./stock.component.scss'],
})
export class StockComponent implements OnInit {
  stocks$: Observable<Stock[]> = this.stockService.getStocks();

  constructor(private stockService: StockService) {}

  ngOnInit(): void {}
}

请注意,上述是示例实现。

英文:

In your code implement the OnDestroy Life cycle hook in angular and unsubsribe it in ngOnDestroy mehthod like below:

import { Component, OnInit, OnDestroy } from &#39;@angular/core&#39;;
import { HttpClient } from &#39;@angular/common/http&#39;;
import { of } from &#39;rxjs&#39;;
import { delay, tap, mergeMap, repeat } from &#39;rxjs/operators&#39;;

@Component({
  selector: &#39;app-root&#39;,
  templateUrl: &#39;./app.component.html&#39;,
  styleUrls: [&#39;./app.component.css&#39;]
})
export class AppComponent implements OnInit, OnDestroy {

  postId;
  private unsubscribe = new Subject&lt;void&gt;();
  callOmni = () =&gt; of(this.pollOmni()).pipe();
  display = response =&gt; {};
  poll = of({}).pipe(
  mergeMap(_ =&gt; this.callOmni()),
  tap(this.display),
  delay(10),
  repeat(),
  takeUntil(this.unsubscribe)
);

  constructor(private http: HttpClient) { } 
  pollOmni() {      
    
    this.http.post&lt;any&gt;(&#39;http://127.0.0.1:8084/api&#39;, { call: &#39;getinfo&#39; }).subscribe(
      data =&gt; {
        this.postId = data;
        console.log(this.postId);
        }),
        error =&gt; {
          console.log(&#39;oops&#39;, error)
        }
     
   
  }

  ngOnInit() {      
    this.poll.subscribe();
  }

ngOnDestroy(): void {
    this.unsubscribe.next(); 
   this.unsubscribe.complete();
  }
}

If the above does not works for you I suggest to implement the template mechanism in Angular Angular Async Pipe Please refer the below sample on usage of pipes in Angular.
Please note that Below is sample implementaions:

  @Component({
      selector: &#39;app-stock&#39;,
      template: `
        &lt;div *ngIf=&quot;stocks$ | async as stocks&quot;&gt;
          &lt;ul&gt;
            &lt;li *ngFor=&quot;let stock of stocks&quot;&gt;
              {{ stock.symbol }}
            &lt;/li&gt;
          &lt;/ul&gt;
        &lt;/div&gt;
      `,
      styleUrls: [&#39;./stock.component.scss&#39;],
    })
    export class StockComponent implements OnInit {
      stocks$: Observable&lt;Stock[]&gt; = this.stockService.getStocks();
    
      constructor(private stockService: StockService) {}
    
      ngOnInit(): void {}
    }

huangapple
  • 本文由 发表于 2023年7月3日 19:59:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/76604533.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定