Skip to main content

Bug Tracker

Side navigation

#11570 closed feature (migrated)

Opened April 09, 2012 03:44PM UTC

Closed October 20, 2014 11:50PM UTC

Move element cache to the element[expando] to avoid cleanup and reduce code.

Reported by: john.david.dalton@gmail.com Owned by: rwaldron
Priority: low Milestone: 1.12/2.2
Component: data Version: git
Keywords: Cc: rwaldron
Blocked by: Blocking:
Description

Soo way back in 2005 Dean Edwards proposed an event system that slapped the listeners on the actual element. This allowed cache to be destroyed once the element was GC'ed.

http://dean.edwards.name/weblog/2005/10/add-event2/

Over the weekend Peter Michaux proposed a similar solution:

https://twitter.com/#!/petermichaux/status/189012245483757568

https://github.com/petermichaux/evento/blob/bd065a9b254a8d14b956ec438dc06c29622c3ef6/src/eventTarget.js#L165

I noticed that jQuery supports events on vanilla objects too so this change would align elements and objects.

The gist is that since jQuery is already adding an expando for a UID they can just use that property as the actual storage for the element.

Then all the code to recursively clean .removed'ed elements event/custom data could be removed as when the element is GC'ed that data is destroyed.

Attachments (0)
Change History (23)

Changed April 09, 2012 03:53PM UTC by rwaldron comment:1

owner: → rwaldron
status: newassigned

I think this is worth investigating and experimenting. I'm going to grab it and work with @jdalton on implementing

Changed April 09, 2012 03:56PM UTC by jdalton comment:2

We may need to confirm the IE6 memory leak issue (or maybe not as that's really IE6 pre SP2) is handled (though if I remember correctly Dean Edwards 05 solution did *not* leak in IE).

Changed June 26, 2012 01:37PM UTC by dmethvin comment:3

Once we exit the two-GC environment of oldIE we can implement this. However, we will still need to do the recursive crawl in at least some cases, to call any special event teardown hooks. We can probably optimize that significantly though, for example an expando flag that indicates whether there are any special events in use for each element.

Changed June 26, 2012 01:38PM UTC by dmethvin comment:4

component: unfiledevent
priority: undecidedlow

Changed July 14, 2012 02:42AM UTC by dmethvin comment:5

milestone: None2.0

Changed April 04, 2013 08:43PM UTC by dmethvin comment:6

cc: → rwaldron

@rwaldron, what should we do with this ticket?

Changed April 04, 2013 08:57PM UTC by rwaldron comment:7

resolution: → fixed
status: assignedclosed

Fixed in 2.0 Data rewrite, which can be read here: https://github.com/jquery/jquery/commits/master/src/data.js

Read backwards from 332a490573bbbd9e7df1381bde8f590240cb8679

Changed April 04, 2013 10:16PM UTC by jdalton comment:8

It looks like it's still relying on data objects internally, that will leak if not discarded via an explicit call when the element is no longer needed. Using the element itself as the object which holds the data object would avoid this (the gist of this issue).

Changed April 04, 2013 10:23PM UTC by rwaldron comment:9

_comment0: The current design in 2.x is designed to support a smooth transition to a WeakMap as soon as they are available in at least 3 browsers (I picked that number arbitrarily). \ \ Putting the data directly on the element would mean exposing jQuery's own interally used data (there are actually two sets of data for every object or element: user and private-interal), which we can't do. As long as user code does all of it's DOM manipulation via jQuery, then data will be correctly cleaned up (removed).1365114279380068

The current design in 2.x is designed to support a smooth transition to a WeakMap as soon as they are available in at least 3 browsers (I picked that number arbitrarily).

Putting the data directly on the element would mean exposing jQuery's own interally used data (there are actually two sets of data for every object or element: user and private-interal), which we can't do. As long as user code does all of its DOM manipulation via jQuery, then data will be correctly cleaned up (removed).

Changed April 04, 2013 10:37PM UTC by jdalton comment:10

(there are actually two sets of data for every object or element: user and private-interal)

I know, the gist of this ticket was to suggest putting all element data (internal/user) on the element. That way there would be no need for the user to manually invoke a cleaning method. This would reduce the code needed for storing data and avoid memory leaks without burdening the dev with cleanup (which when overlooked, which is easy, can cause leaks that are not so easy to track down).

Changed April 04, 2013 10:53PM UTC by rwaldron comment:11

Replying to [comment:10 jdalton]:

> (there are actually two sets of data for every object or element: user and private-interal) I know, the gist of this ticket was to suggest putting all element data (internal/user) on the element. That way there would be no need for the user to manually invoke a cleaning method. This would reduce the code needed for storing data and avoid memory leaks without burdening the dev with cleanup (which when overlooked, which is easy, can cause leaks that are not so easy to track down).

If user code can get at all of the jQuery-specific internal data, then we can't make any guarantees stability or reliability (http://bugs.jquery.com/ticket/11945, http://forum.jquery.com/topic/what-s-the-rationale-of-not-exposing-object-s-events-handlers-collections). Trust me, I wish it was that easy :(

I always appreciate your input and feedback, but in this case we can't expose the jQuery-specific internal data on "owner" object.

Related, but not directly... I'm not sure what you mean by "need for the user to manually invoke a cleaning method"? This happens automatically with jQuery dom manip methods (where appropriate). The only time it won't happen is if user code uses DOM APIs directly, which is out of scope for jQuery.

Changed April 04, 2013 11:15PM UTC by dmethvin comment:12

@jdalton, for the general case we still need to call our jQuery.cleanData() method in manipulation.js at least for situations like special events where we guarantee a teardown hook. Also consider our semantics for .remove() which say that when you remove elements from the document it removes both the events and data, whereas .detach() does not.

So we have to go through the loop part of the cleanData code regardless, but perhaps attaching the data to the element would let us skip some steps? If it made a significant performance difference I'd be interested in seeing an implementation, even if it "exposed" data to some extent. In doing perf testing on web apps and sites it's not uncommon to see cleanData high on the list, especially with MV* frameworks that update big DOM chunks.

Changed April 04, 2013 11:22PM UTC by rwaldron comment:13

We could "patchwelcome" this ticket, but the patch would have to pass all of the existing data tests as-is.

Changed April 05, 2013 12:11AM UTC by jdalton comment:14

Related, but not directly... I'm not sure what you mean by "need for the user to manually invoke a cleaning method"?

I was thinking of devs having to use .remove() and friends instead of say simply el.innerHTML=''. You're correct though if they were diligent and used only lib API it is managed.

If user code can get at all of the jQuery-specific internal data, then we can't make any guarantees stability or reliability

As for exposing data, pre 2.0, jQuery.cache existed so I'm not sure how that fits into the guarantees of stability or reliability.

As an aside, jQuery hasn't been a big user of hasOwnProperty checks so couldn't someone manipulate the Object.prototype and populate data values? Does that fit with stability/reliability guarantees?

Also I wanna +1 @dmethvin perf concern.

Changed April 05, 2013 12:38AM UTC by rwaldron comment:15

As for exposing data, pre 2.0, jQuery.cache existed so I'm not sure how that fits into the guarantees of stability or reliability.

In jQuery 2.x there is no jQuery.cache for this very reason :)

As an aside, jQuery hasn't been a big user of hasOwnProperty checks so couldn't someone manipulate the Object.prototype and populate data values? Does that fit with stability/reliability guarantees?

Sure, but that falls under the official Won't Fix :D http://contribute.jquery.org/wont-fix/

Changed April 05, 2013 04:25AM UTC by jdalton comment:16

Sure, but that falls under the official Won't Fix :D

Yap, lots of things are out of scope, but that makes the "guarantee" more lip service than substance. So in this case I think it's more beneficial to store the data on the element instead.

With that said, I don't have time to investigate at the moment, so if resources are limited the issue can be noted for future reference.

Changed May 20, 2013 10:06PM UTC by rwaldron comment:17

milestone: 2.0
resolution: fixed
status: closedreopened

Changed June 03, 2013 01:53PM UTC by dmethvin comment:18

milestone: → 1.11/2.1
status: reopenedopen

Changed November 04, 2013 02:11PM UTC by jzaefferer comment:19

_comment0: We discussed this in Amsterdam. jQuery UI currently depends on cleanData to hook its widget removal in: Whenever an element is removed that is a widget, it calls the destroy() method of the widget, for example to unbind event handlers from the document. \ \ Whatever the solution for this looks like needs to provide some alternative hook for jQuery UI.1383575653989533

We discussed this in Amsterdam. jQuery UI currently depends on cleanData to hook its widget removal in: Whenever an element is removed that is a widget, it calls the destroy() method of the widget, for example to unbind event handlers from the document.

Whatever the solution for this looks like needs to provide some alternative hook for jQuery UI. See also #12213

Changed November 10, 2013 10:09PM UTC by m_gol comment:20

I've read the comments and it seems there's still an issue with teardown hooks not being invoked if an element is removed via raw DOM methods. Can we overcome this difficulty?

As for the safety guarantees, I mostly agree with jdalton; we're unable to provide complete protection anyway so if (!) it's possible for jQuery-created & handled elements to cooperate with native DOM methods I'm +1 on this one.

Changed December 16, 2013 04:57PM UTC by dmethvin comment:21

milestone: 1.11/2.11.next/2.next

I'm not worried about complete protection, we're mainly trying to avoid walking all the elements in the tree when we don't have to. If someone mingles jQuery with raw DOM methods to manipulate the document they will need to understand the consequences.

Changed March 03, 2014 03:46PM UTC by dmethvin comment:22

component: eventdata
milestone: 1.next/2.next1.12/2.2

Changed October 20, 2014 11:50PM UTC by m_gol comment:23

resolution: → migrated
status: openclosed