Skip to content

Global event unbinding breaks other plugins #63

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ValentinH opened this issue May 29, 2015 · 15 comments
Closed

Global event unbinding breaks other plugins #63

ValentinH opened this issue May 29, 2015 · 15 comments

Comments

@ValentinH
Copy link
Member

In this line (and some other), event listener is unbind in this way:

$document.off('mousemove');

The problem is that it removes all the listener on the page and so, it can break other plugins using this event.

The good practice is to namespace your event like this:

$document.on('mousemove.rzslider', angular.bind(this, this.onMove, pointer));

//and later
$document.off('mousemove.rzslider');
@rzajac
Copy link
Member

rzajac commented May 29, 2015

As far as I know AngularJs .on does not support namespaces. https://docs.angularjs.org/api/ng/function/angular.element

@ValentinH
Copy link
Member Author

Damn that sucks. The problem is that the only other way not to unbind globally is to unbind providing the bound function. But this is more constraining and not always possible!

Still this is a problem since it brokers other plugins, such as Highcharts.

Moreover, there are memory leak issues due to other listeners that are not unbound on scope destroy (a recent commit added unbindings on document destroy but some events are missing and document is not enough since we are doing SPA). I was planning to do a PR but it uses namespacing...

rzajac added a commit that referenced this issue May 31, 2015
@rzajac
Copy link
Member

rzajac commented May 31, 2015

@ValentinH with 703ad38 I have changed the way the binding / unbinding work. Can you take a look if the memory leak problem has been solved?

@ValentinH
Copy link
Member Author

I just made a test with that last version and I still have leaks problems. I'm checking what is missing compared to the modifications I made to fix them and I'll submit a PR.

@ValentinH
Copy link
Member Author

I found the issue, it is the unbinding on the window that misses an argument.

angular.element($window).off(calcDimFn);

should be replaced by

angular.element($window).off('resize', calcDimFn);

Another remark: regarding the memory leaks issues, my tests have shown that the only important
unbindings are the one on document and window. So in my opinion, the code for the destroy event should simply be:

this.scope.$on('$destroy', function() {
    angular.element($window).off('resize', calcDimFn);
});

Indeed, the binding on the scope and on the element (and its children) of the directive are managed by angular: http://stackoverflow.com/questions/26983696/angularjs-does-destroy-remove-event-listeners

[Edit]: I have also read in several places that ensuring ourselves the unbinding was a good practice to prevent any bug. Indeed, in some rare cases, Angular might misses some unbinding so doing that ourselves is safer.

@rzajac rzajac closed this as completed in f253533 Jun 1, 2015
@rzajac
Copy link
Member

rzajac commented Jun 1, 2015

The weird thing is when I do two JS Heap snapshots in Chrome i see that the memory used is still increased.

@ValentinH
Copy link
Member Author

What is your test scenario?

Mine was to navigate between two views, A and B where A contains a slider. Once on B, the all scope of A was still in memory in the previous version due to the leaks in angular-slider. Now, the A scope is correctly deleted when navigating to B.

@rzajac
Copy link
Member

rzajac commented Jun 1, 2015

Using Chrome

  1. Load the demo site
  2. Take heap snapshot
  3. Play with slider handles for a few seconds
  4. Wait 2 - 3 seconds
  5. Take heap snapshot and compare to first one

@ValentinH
Copy link
Member Author

Yeap I just tried this scenario and there are a few elements that are created during the sliders manipulation but nothing important in my opinion.

If you take 3 snapshots and check the objects that are still in Snap 3 but created between 1 and 2, there are nothing big. More importantly, I don't see any DOM Element that are still here because attached to a Scope object. So, it is OK AFAIK.

In my application, before you fix the leaks, all the scope object was kept between each view so after a lot of page views the application was containing something like a hundred scopes in memory. Now it is fixed.

@e-cloud
Copy link
Contributor

e-cloud commented Sep 13, 2015

[Edit]: I have also read in several places that ensuring ourselves the unbinding was a good practice to prevent any bug. Indeed, in some rare cases, Angular might misses some unbinding so doing that ourselves is safer.

@ValentinH, would you mind showing some example that angular misses some unbindings

@ValentinH
Copy link
Member Author

Nope I don't. As I said it is only good practice, and use the term "might"... I don't have proof but it doesn't cost much to do it ourselves...

@e-cloud
Copy link
Contributor

e-cloud commented Sep 13, 2015

Yeah, i get it.
However, IMHO, part of the good coding style is to keep the code clean and do the necessary thing. Since we develop something based on angular which itself does a great job most of time, and there is no evidence of that problem/bug, we don't need to do that. Even if the bug exists, we should make an issue to angular, and we can do some hack/dirty work temporarily. Once the issue is fixed, we ought to go on the right way.
ehhh, just my opinion.

@ValentinH
Copy link
Member Author

Are you talking about these unbindings: https://github.com/rzajac/angularjs-slider/blob/master/rzslider.js#L355-L358 .

I can retest the leaks when removing them on Monday but I think they were necessary...

@e-cloud
Copy link
Contributor

e-cloud commented Sep 14, 2015

https://github.com/rzajac/angularjs-slider/blob/master/rzslider.js#L325-L361
Nope, i'm taking about the deRegFuns and the unRegFn, what you have mentioned above of course they are necessary 'cause they won't be unbinded automatically

@ValentinH
Copy link
Member Author

Oh I see, my comment was only referring to DOM event actually and the lines in my previous comment should be useless since this DOM element are created as children of the Directive and so will be deleted... I agree about the unbinding of watches, they are probably useless.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants