-
Notifications
You must be signed in to change notification settings - Fork 299
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
Owned weak event listener to prevent memory leak (using EventListenerOptions) #243
Comments
I get the intent and the goal here, but I think the approach adds a level of assumption that may not be worth implementing, especially for, imo, is such a small use case. This also makes it easy to lead to bad practices, which is already easy to do in the world of JavaScript, unfortunately. :) I guess my point here is that removing listeners when they are added should be required always if the desire is to prevent memory leaks. It sounds like your intent here is to have to write less code, which is arguable of whether thats a good enough reason. Regardless of the reason though, I think the code should at the very minimum require an engineer to explicitly opt-in for this functionality, rather than assume that an engineer wants it, similarly to WeakMap or WeakSets. Additionally, passing an |
Actually, if the event target and the event listeners have same life time (or event listeners live longer), this is usually not required -- GC of event target usually means GC of event listeners. This is the case if all event listeners of a UI component are only added to component the and its children. But it can be problematic if the event target outlives its event listeners, e.g. event target is JS is a language with GC, but manual event listener management sometimes defeats the goal of GC. This proposal trys to make event listeners more GC-friendly.
I choose "owner“ to mean "Although this event listener logically belongs to Node x, it has to be added to one of x's ancestors. I want this event listener to die after Node x dies."
This functionality does require opt-in: if you omit the |
Sorry for the confusion. I'm speaking of only scenarios where the event target outlives its event listeners. You see this a lot in single page web applications which are beginning to be more common, so event listening GC does not apply for these scenarios. Two things come to mind with the
|
I think developers should avoid event target outliving its event listeners where possible, no matter SPA or not. If not possible, try owned weak event listener :). If all failed, I think it means the app is not modulized well. I think
How? The event target and event listener don't known the logical owner of the event listener unless we specify one. |
I like the idea of having the possibility to have weak listeners, it can be useful in some cases, but It can trick you into think it would prevent a leak, but in fact it would cause one. Lets say you added a event on document to close a popup, and the you remove the popup from the DOM, the GB trashes the listener, this means the listener never gets called, but you used that listener to teardown your thing and maybe sub components, but now they will live forever as ghosts "components". |
@victornpb Sorry for later reply. You are right. Never assume a weak event listener will be triggered at least once. |
I think you need to have more compelling evidence that this is a desirable feature. E.g., show adoption of it by widely used frameworks and popular sites. |
@annevk One of the evidence outside web platform is weak event in .net: |
You can certainly implement something that deactivates event listeners when a corresponding node is removed. You might even simply remove the listener. You'd lose ordering, but you'd at least not leak. In any event, I'm going to close this. More experience by libraries is needed for this to be considered. |
@annevk I'm not sure what you mean. If I want to implement
I have to reference |
If popupElem controls adding and removing the listener you don't have that problem. |
It is not always possible. E.g. one of the ancestor of popupElem is removed before popupElem could clean up the listener. |
The problem
In order to implement a UI component such as popup menu or tooltip, it is usually necessary to add an event listener on an ancestor node (e.g.
document
) to hide/remove the component when the user click/touch outside of the component. However, it is a significant burden to make sure the event listener on the ancestor node is removed when the component is to be hidden/removed. For example, if some uncareful code removed one of the ancestor nodes of the component from the tree without also remove the listener ondocument
, then the listener is leaked.It would be nice if the event listener on the ancestor node is automatically removed by UA after the component is removed.
Prior art: weak event listener
There is no concept of weak event listener in DOM, HTML or ECMAScript standards yet, though ActionScript 3 and .Net already implemented it to prevent leak of listener. In short, a weak event listener is an event listener object that is weakly referenced by the event source and/or the runtime. If the weak event listener is no longer strongly referenced by user's code except the the event source, it is legitimate to be removed from the event source and GC'ed.
Weak event listener can be useful to solve the problem mentioned above: we can add an event listener weakly on the ancestor node and let the component reference the event listener strongly. After the component is removed and GC'ed, the event listener will also be removed from the ancestor node.
However, weak event listener exposes indeterministic behavior of GC to user's code: weak event listener is still working after it is no longer strongly referenced by user's code but not GC'ed yet.
Proposed solution: owned weak event listener
This solution is described as follow:
To implement this feature, the owner Node should hold strong references to its owned event listeners, and the event target Node may hold weak references to the turple of event listener and its owner.
Note that this feature is deterministic: an event listener won't be GC'ed before its owner can be GC'd; The the event listener is turned off when its owner is removed from the document, not when it is GC'ed.
The API looks like:
dictionary AddEventListenerOptions: EventListenerOptions { //... Node owner = null; };
To solve the problem mentioned at the beginning, just let the owner be the component:
The text was updated successfully, but these errors were encountered: