你需要取消订阅Angular 2的http调用来防止内存泄漏吗?

 fetchFilm(index) {
        var sub = this._http.get(`http://example.com`)
            .map(result => result.json())
            .map(json => {
                dispatch(this.receiveFilm(json));
            })
            .subscribe(e=>sub.unsubscribe());
            ...

当前回答

所以答案是不,你不需要。Ng2会自行清理。

Http服务源,来自Angular的Http XHR后端源:

注意它在得到结果后是如何运行complete()的。这意味着它实际上在完成时取消订阅。所以你不需要自己动手。

下面是一个测试来验证:

  fetchFilms() {
    return (dispatch) => {
        dispatch(this.requestFilms());

        let observer = this._http.get(`${BASE_URL}`)
            .map(result => result.json())
            .map(json => {
                dispatch(this.receiveFilms(json.results));
                dispatch(this.receiveNumberOfFilms(json.count));
                console.log("2 isUnsubscribed",observer.isUnsubscribed);
                window.setTimeout(() => {
                  console.log("3 isUnsubscribed",observer.isUnsubscribed);
                },10);
            })
            .subscribe();
        console.log("1 isUnsubscribed",observer.isUnsubscribed);
    };
}

正如预期的那样,你可以看到它总是在获得结果并完成可观察操作符后自动取消订阅。这发生在一个超时(#3),所以我们可以在它全部完成和完成时检查可观察对象的状态。

结果是

所以,Ng2自动退订时不会有泄漏!

值得一提的是:这个可观察对象被归类为有限的,与无限的可观察对象相反,无限的可观察对象是一个无限的数据流,可以像DOM点击侦听器一样发出。

谢谢@rubyboy的帮助。

其他回答

所以答案是不,你不需要。Ng2会自行清理。

Http服务源,来自Angular的Http XHR后端源:

注意它在得到结果后是如何运行complete()的。这意味着它实际上在完成时取消订阅。所以你不需要自己动手。

下面是一个测试来验证:

  fetchFilms() {
    return (dispatch) => {
        dispatch(this.requestFilms());

        let observer = this._http.get(`${BASE_URL}`)
            .map(result => result.json())
            .map(json => {
                dispatch(this.receiveFilms(json.results));
                dispatch(this.receiveNumberOfFilms(json.count));
                console.log("2 isUnsubscribed",observer.isUnsubscribed);
                window.setTimeout(() => {
                  console.log("3 isUnsubscribed",observer.isUnsubscribed);
                },10);
            })
            .subscribe();
        console.log("1 isUnsubscribed",observer.isUnsubscribed);
    };
}

正如预期的那样,你可以看到它总是在获得结果并完成可观察操作符后自动取消订阅。这发生在一个超时(#3),所以我们可以在它全部完成和完成时检查可观察对象的状态。

结果是

所以,Ng2自动退订时不会有泄漏!

值得一提的是:这个可观察对象被归类为有限的,与无限的可观察对象相反,无限的可观察对象是一个无限的数据流,可以像DOM点击侦听器一样发出。

谢谢@rubyboy的帮助。

取消订阅是必须的,如果你想在所有的网络速度上有一个确定的行为。

想象一下组件A是在一个选项卡中呈现的——你点击一个按钮发送一个“GET”请求。响应返回需要200毫秒。所以,你在任何时候都可以安全地关闭选项卡,因为机器会比你更快&在选项卡关闭和组件A被销毁之前处理并完成http响应。

How about on a very slow network? You click a button, the 'GET' request takes 10 seconds to receive its response, but 5 seconds into waiting you decide to close the tab. That will destroy component A to be garbage-collected at a later time. Wait a minute!, we did not unsubscribe -- now 5 seconds later, a response comes back and the logic in the destroyed component will be executed. That execution is now considered out-of-context and can result in many things including very low performance and data/state corruption.

因此,最佳实践是使用takeUntil(),并在组件销毁时从http调用订阅中取消订阅。

注意:

RxJS不是Angular特有的 模板中使用的异步管道会在销毁时自动取消订阅 取消订阅多次没有负面影响,除了额外的无操作呼叫

import { Component, OnInit, OnDestroy } from '@angular/core';
import { HttpClient } from '@angular/common/http';

import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

interface User {
  id: string;
  name: string;
  age: number;
}

@Component({
  selector: 'app-foobar',
  templateUrl: './foobar.component.html',
  styleUrls: ['./foobar.component.scss'],
})
export class FoobarComponent implements OnInit, OnDestroy {
  private user: User = null;
  private destroy$ = new Subject();

  constructor(private http: HttpClient) {}

  ngOnInit() {
    this.http
      .get<User>('api/user/id')
      .pipe(takeUntil(this.destroy$))
      .subscribe(user => {
        this.user = user;
      });
  }

  ngOnDestroy(): void {
    this.destroy$.next();  // trigger the unsubscribe
    this.destroy$.complete(); // finalize & clean up the subject stream
  }
}

你不应该取消自动完成的观察对象的订阅(例如Http,调用)。但是有必要取消订阅无数个可观察对象,比如Observable.timer()。

调用unsubscribe方法更像是取消一个正在进行的HTTP请求,因为这个方法在底层XHR对象上调用abort方法,并在load和error事件上删除侦听器:

// From the XHRConnection class
return () => {
  _xhr.removeEventListener('load', onLoad);
  _xhr.removeEventListener('error', onError);
  _xhr.abort();
};

也就是说,取消订阅会删除听众……所以这可能是一个好主意,但我不认为这是必要的单一请求;-)

希望它能帮助到你, 亨利

经过一段时间的测试,阅读HttpClient的文档和源代码。

HttpClient: https://github.com/angular/angular/blob/master/packages/common/http/src/client.ts

a . h .出口:有何不同

HttpClientModule: https://indepth.dev/exploring-the-httpclientmodule-in-angular/

Angular大学:https://blog.angular-university.io/angular-http/

这种特殊类型的可观察对象是单值流:如果HTTP请求成功,这些可观察对象将只发出一个值,然后完成

而整个问题的答案是“我需要退订吗?”

视情况而定。 Http调用内存泄漏不是一个问题。 问题是回调函数中的逻辑。

例如:路由、登录。

如果您的呼叫是一个登录呼叫,您不必“取消订阅”,但您需要确保如果用户离开页面,您可以在用户缺席的情况下正确处理响应。


this.authorisationService
      .authorize(data.username, data.password)
      .subscribe((res: HttpResponse<object>) => {
          this.handleLoginResponse(res);
        },
        (error: HttpErrorResponse) => {
          this.messageService.error('Authentication failed');
        },
        () => {
          this.messageService.info('Login has completed');
        })

从恼人到危险

现在,想象一下,网络比平时慢,调用时间长了5秒,用户离开登录视图,转到“支持视图”。

组件可能不是活动的,但订阅是活动的。在响应的情况下,用户将突然被重新路由(取决于您的handlerresponse()实现)。

这可不太好。

再想象一下,用户离开了pc,认为他还没有登录。但是当用户登录时,就会出现安全问题。

如果不取消订阅,你能做什么?

使你的调用依赖于视图的当前状态:

  public isActive = false;
  public ngOnInit(): void {
    this.isActive = true;
  }

  public ngOnDestroy(): void {
    this.isActive = false;
  }

用户.pipe(takeWhile(value => this.isActive))以确保仅在视图处于活动状态时才处理响应。


this.authorisationService
      .authorize(data.username, data.password).pipe(takeWhile(value => this.isActive))
      .subscribe((res: HttpResponse<object>) => {
          this.handleLoginResponse(res);
        },
        (error: HttpErrorResponse) => {
          this.messageService.error('Authentication failed');
        },
        () => {
          this.messageService.info('Login has completed');
        })

但是如何确保订阅不会导致内存泄漏呢?

如果应用了“teardownLogic”,则可以记录日志。

当订阅为空或未订阅时,将调用订阅的teardownLogic。


this.authorisationService
      .authorize(data.username, data.password).pipe(takeWhile(value => this.isActive))
      .subscribe((res: HttpResponse<object>) => {
          this.handleLoginResponse(res);
        },
        (error: HttpErrorResponse) => {
          this.messageService.error('Authentication failed');
        },
        () => {
          this.messageService.info('Login has completed');
    }).add(() => {
        // this is the teardown function
        // will be called in the end
      this.messageService.info('Teardown');
    });

你不必取消订阅。 您应该知道您的逻辑中是否存在问题,这可能会导致您的订阅出现问题。照顾好他们。在大多数情况下,这不会是一个问题,但特别是在像自动化这样的关键任务中,你应该注意意外的行为,无论是“取消订阅”还是其他逻辑,如管道或条件回调函数。

为什么不总是退订呢?

假设您提出了一个put或post请求。服务器以任何一种方式接收消息,只是响应需要一段时间。取消订阅,不会撤销帖子或放。 但当您取消订阅时,您将没有机会处理响应或通知用户,例如通过对话或祝酒词/消息等。

这使得用户相信,put/post请求没有完成。

这要看情况。如何处理这些问题是你的设计决定。