是否有必要取消订阅由Http方法创建的可观察对象?

问题描述 投票:141回答:7

您是否需要取消订阅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());
            ...
angular memory-leaks rxjs angular2-http
7个回答
203
投票

所以答案是否定的,你没有。 Ng2将自己清理它。

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

enter image description here

注意它在获得结果后如何运行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),因此我们可以检查observable何时完成并完成。

结果

enter image description here

因此,当Ng2自动取消订阅时,不存在任何泄漏!

很高兴提到:这个Observable被归类为finite,与infinite Observable相反,click是一个无限的数据流,可以像DOM subscribe监听器一样发出。

谢谢@rubyboy对此有所帮助。


46
投票

What are you people talking about!!!

好的,有两个理由可以取消订阅任何可观察的内容。似乎没有人谈论非常重要的第二个原因!

1)清理资源。正如其他人所说,这对HTTP可观察量来说是一个微不足道的问题。它只是清理自己。

2)防止subscribe()处理程序运行。

(对于HTTP,这实际上也会在浏览器中取消请求 - 所以它不会浪费时间阅读响应。但这实际上是我的主要观点。)

数字2的相关性将取决于您的订阅处理程序的作用:

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

考虑一些情况:

1)登录表格。输入用户名和密码,然后单击“登录”。如果服务器很慢并且你决定点击Escape以关闭对话框怎么办?您可能会认为您没有登录,但是如果在您点击转义后返回了http请求,那么您仍将执行您在那里拥有的任何逻辑。这可能导致重定向到帐户页面,设置了不需要的登录cookie或令牌变量。这可能不是您的用户所期望的。

2)“发送电子邮件”表格。

如果'sendEmail'的unsubscribe()处理程序执行触发“您的电子邮件已发送”动画,将您转移到其他页面或尝试访问已处置的任何内容,您可能会遇到异常或不需要的行为。

另外要注意不要假设unsubscribe()意味着'取消'。一旦HTTP消息在飞行中,onDestroy()将不会取消HTTP请求,如果它已经到达您的服务器。它只会取消回复给您的回复。电子邮件可能会被发送。

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

3)被破坏/关闭的Angular组件。除非您在Subscription中取消订阅,否则当时仍在运行的任何http observable都将完成并运行其逻辑。后果是否微不足道将取决于您在订阅处理程序中执行的操作。如果您尝试更新不存在的内容,则可能会出错。

有时,如果组件被丢弃,您可能会有一些您想要的操作,有些则不会。例如,对于发送的电子邮件,您可能会发出'swoosh'声音。您可能希望即使组件已关闭也可以播放,但如果您尝试在组件上运行动画,则会失败。在这种情况下,订阅中的一些额外的条件逻辑将是解决方案 - 并且您不希望取消订阅http observable。

因此,在回答实际问题时,不需要这样做以避免内存泄漏。但是你需要(通常)这样做以避免因运行可能引发异常或破坏应用程序状态的代码而触发不必要的副作用。

提示:closed包含_isDestroyed布尔属性,可能在高级情况下有用。对于HTTP,它将在完成时设置。在Angular中,在某些情况下在ngDestroy中设置subscribe属性可能很有用,可以通过new Subscription()处理程序进行检查。

提示2:如果处理多个订阅,您可以创建一个特殊的add(...)对象和unsubscribe任何其他订阅 - 所以当您取消订阅主要订阅时,它也将取消订阅所有添加的订阅。


21
投票

调用abort方法是取消正在进行的HTTP请求,因为此方法在底层XHR对象上调用// From the XHRConnection class return () => { _xhr.removeEventListener('load', onLoad); _xhr.removeEventListener('error', onError); _xhr.abort(); }; 并删除有关加载和错误事件的侦听器:

unsubscribe

那就是说,packages/common/http/src/jsonp.ts删除了听众......所以这可能是一个好主意,但我不认为这对于单个请求是必要的;-)

希望它对你有帮助,蒂埃里


11
投票

另外,使用新的HttpClient模块,仍然保持相同的行为Observable.timer()


8
投票

您不应该取消订阅自动完成的可观察量(例如,Http,调用)。但是有必要取消订阅像this这样的无限可观测量。


2
投票

你一定要阅读qazxswpoi文章。它向您展示了为什么您应该始终取消订阅甚至http。

如果在创建请求之后但在从后端收到答案之前您认为该组件是不必要的并将其销毁,则您的订阅将保留对该组件的引用,从而产生导致内存泄漏的机会。

更新

上面的肯定似乎是真的,但无论如何,当答案回来时,无论如何都会销毁http订阅


-2
投票

RxJS observable基本上是关联的,因此您可以订阅它。当我们创建observable和我们完成它的运动时,observable会自动关闭并取消订阅。

它们以与观察者相同的方式工作,但顺序完全不同。当组件被破坏时,更好的做法是取消订阅它们。我们随后可以通过例如。这一点。$ manageSubscription.unsubscibe()

如果我们已经创建了类似于下面提到的语法的observable,例如

** return new Observable((observer)=> {** //它在寒冷状态下可观察** observer.complete()**})**

© www.soinside.com 2019 - 2024. All rights reserved.