你需要取消订阅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());
            ...

当前回答

有助于理解这一点的一个很好的方面是,除非调用订阅函数,否则不会发出HTTP请求。虽然本页上的答案似乎建议了两种不同的做法,但它真的没有多大意义 正如angular文档所指出的那样,所需的行为将由异步管道控制(尽管在后面的“发出DELETE请求”一节中会提到):

AsyncPipe自动为您订阅(和取消订阅)。

事实上,在文档中更难找到通过调用unsubscribe函数显式取消订阅这些可观察对象的例子。

其他回答

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

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

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

希望它能帮助到你, 亨利

所以答案是不,你不需要。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的帮助。

你们这些人在说什么!!

所以我们有两个理由取消订阅任何可观察对象。似乎没有人谈论非常重要的第二个原因!

清理资源。正如其他人所说,这对于HTTP可观察对象来说是一个可以忽略不计的问题。它会自己清理的。

阻止订阅处理程序运行。

注意,使用HTTP可观察对象,当你取消订阅时,它会在浏览器中为你取消底层请求(你会在网络面板中看到“取消”的红色部分)。这意味着不会浪费时间下载或解析响应。但这实际上是我下面主要观点的题外话。

2的相关性将取决于你的订阅处理程序做什么:

如果subscribe()处理函数有任何不希望看到的副作用 如果调用它的对象被关闭或被释放,那么你必须取消订阅(或添加条件逻辑)来阻止它被执行。

考虑以下几个案例:

一个登录表单。输入用户名和密码,然后点击“登录”。如果服务器很慢,而你决定按Escape键关闭对话框怎么办?你可能会假设你没有登录,但如果http请求在你点击escape之后返回,那么你仍然会执行你在那里的任何逻辑。这可能会导致重定向到帐户页面,设置不需要的登录cookie或令牌变量。这可能不是您的用户所期望的。 “发送电子邮件”表单。

如果订阅处理程序为'sendEmail'做了一些事情,如触发'您的电子邮件已发送'动画,将您转移到不同的页面或试图访问任何已处理的内容,您可能会得到异常或不想要的行为。

还要注意不要假定unsubscribe()表示“取消”。一旦HTTP消息在运行中unsubscribe()将不会取消HTTP请求如果它已经到达您的服务器。它只会取消返回给您的响应。邮件很可能会被发送出去。

如果您创建订阅以直接在UI组件中发送电子邮件,那么您可能希望在处理时取消订阅,但如果电子邮件是由非UI集中式服务发送的,那么您可能不需要这样做。

一个被销毁/关闭的Angular组件。任何仍在运行的http可观察对象都将完成并运行它们的逻辑,除非你在onDestroy()中取消订阅。结果是否微不足道取决于您在订阅处理程序中所做的工作。如果你试图更新一些不存在的东西,你可能会得到一个错误。

有时,如果组件被释放,您可能需要一些操作,而有些则不需要。例如,你发出的电子邮件可能会发出“嗖嗖”的声音。你可能想要在组件关闭时播放这个,但是如果你试图在组件上运行动画,它会失败。在这种情况下,订阅内部的一些额外的条件逻辑将是解决方案-你不会想要取消订阅http可观察对象。

所以在实际问题的答案中,不,你不需要这样做来避免内存泄漏。但您需要(经常)这样做,以避免运行代码引发不必要的副作用,这些代码可能会抛出异常或破坏应用程序状态。

提示:订阅包含一个关闭的布尔属性,在高级情况下可能有用。对于HTTP,这将在它完成时设置。在Angular中,在某些情况下在ngDestroy中设置_isDestroyed属性可能会很有用,它可以被你的订阅处理程序检查。

技巧2:如果处理多个订阅,您可以创建一个特别的新订阅()对象,并向其添加(…)任何其他订阅-因此当您从主订阅中取消订阅时,它也将取消所有添加的订阅。

有助于理解这一点的一个很好的方面是,除非调用订阅函数,否则不会发出HTTP请求。虽然本页上的答案似乎建议了两种不同的做法,但它真的没有多大意义 正如angular文档所指出的那样,所需的行为将由异步管道控制(尽管在后面的“发出DELETE请求”一节中会提到):

AsyncPipe自动为您订阅(和取消订阅)。

事实上,在文档中更难找到通过调用unsubscribe函数显式取消订阅这些可观察对象的例子。

同样对于新的HttpClient模块,保持相同的行为