Is it necessary to unsubscribe from observables cr

2019-01-01 08:45发布

Do you need to unsubscribe from Angular 2 http calls to prevent memory leak?

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

6条回答
何处买醉
2楼-- · 2019-01-01 09:28

What are you people talking about!!!

OK so there's two basic reasons to unsubscribe from any observable. Nobody seems to be talking much about the second!

1) Clean up resources. As others have said this is a negligible problem for HTTP observables. It'll just clean itself up.

2) Prevent the subscribe handler from being run.

The importance of number 2 is going to depend upon what your handler does:

If your subscribe() handler function has any kind of side effect that is undesired when the calling component is closed then you must unsubscribe (or add conditional logic) to stop it from being called.

Consider a few cases:

1) A login form. You enter username and password and click 'Login'. What if the server is slow and you decide to hit Escape to close the dialog? You'll probably assume you weren't logged in, but if the http request returned after you hit escape then then you will still execute whatever logic you have there. This may result in a redirect, an unwanted login cookie or token variable being set. This is probably not what your user expected.

2) A 'send email' form. Once the HTTP message is in-flight it's important to understand that unsubscribe() will NOT cancel the HTTP request. It's already on its way - and that's nothing to do with Angular or RxJS - it's just how the internet works. It will get to your server, and the email will get sent. (You'd have to implement some kind of delayed send mechanism like Gmail's Undo button does if you need more sophisticated behavior.)

If the subscribe handler for 'sendEmail' does something like trigger a 'Your email is sent' animation, transfer you to a different route or accesses another observable that has been disposed then you will get exceptions or unwanted behavior.

Sometimes you may be somewhere in between where some actions you'd want, and some you wouldn't. For example maybe you have a 'swoosh' sound for a sent email. You'd probably want this to play even if the component was closed, but if you try to run an animation on the component that was just closed it would fail. In that case some extra conditional logic inside subscribe would be the solution - and you would NOT want to unsubscribe the http observable.

So in answer to the actual question, no you don't need to do it to avoid memory leaks. But you need to do it (usually) to avoid unwanted side effects being triggered or running code that may throw exceptions and even corrupt your application state.

Tip: The Subscription contains a closed boolean property that may be useful in certain cases. For HTTP this will be set when it completes. Also sometimes it may be useful to set a _isDestroyed property after a component is destroyed which subscribe can check to decide what not to run.

查看更多
爱死公子算了
3楼-- · 2019-01-01 09:35

You shouldn't unsubscribe from observables that completes automatically (e.g Http, calls). But it's necessary to unsubscribe from infinite observables like Observable.timer().

查看更多
公子世无双
4楼-- · 2019-01-01 09:44

So the answer is no, you don't. Ng2 will clean it up itself.

The Http service source, from Angular's Http XHR backend source:

enter image description here

Notice how it runs the complete() after getting the result. This means it actually unsubscribes on completion. So you don't need to do it yourself.

Here is a test to validate:

  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);
    };
}

As expected, you can see that it is always unsubscribed automatically after getting the result and finishing with the observable operators. This happens on a timeout (#3) so we can check the status of the observable when it's all done and completed.

And the result

enter image description here

So, no leak would exist as Ng2 auto unsubscribes!

Nice to mention: This Observable is categorized as finite, on contrary to the infinite Observablewhich is an infinite stream of data can be emitted like DOM click listener for example.

THANKS, @rubyboy for help on this.

查看更多
爱死公子算了
5楼-- · 2019-01-01 09:46

Also with the new HttpClient module, remains the same behaviour packages/common/http/src/jsonp.ts

查看更多
深知你不懂我心
6楼-- · 2019-01-01 09:47

Calling the unsubscribe method is rather to cancel an in-progress HTTP request since this method calls the abort one on the underlying XHR object and remove listeners on the load and error events:

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

That said, unsubscribe removes listeners... So it could be a good idea but I don't think that it's necessary for a single request ;-)

Hope it helps you, Thierry

查看更多
看淡一切
7楼-- · 2019-01-01 09:47

RxJS observable are basically associated and work accordingly you subscribe it. When we create the observable and the movement we complete it, observable automatically gets closed and unsubscribed.

We don't have to explicitly invoke unsubscribe method.you can check the status of observable by using closed method.

查看更多
登录 后发表回答