开发者

Why Doesn't JQuery Expose its UUID Functionality?

Underneath the hood JQuery uses a map of "UUIDs" (just a counter it maintains as jQuery.uuid) to work around the well-known memory leak issues browsers have when yo开发者_如何学JAVAu attach a property to a tag in the DOM from Javascript. In lieu of doing so, JQuery uses the $.data(tag, name, value) to store data in a map keyed off of the uuid (a key that can be determined by checking tag[jQuery.expando]).

While $.data() is very useful, there are times you want to map data to tags without dumping that data into one global bucket - you want your own smaller bucket of data that you can, for example, check the length of or loop through.

As a contrived example, suppose you have icons that rotate through one of 4 states when clicked. When one is in state 2, you want to add it to an array of icons in state 2. The most obvious way to do so is to add the tag to an array; however doing so would create a memory leak. You could call $.data() on the checkbox, but that doesn't quite accomplish what you're trying to do - you'd have to loop through all the checkboxes checking $.data() against them to figure out which are and aren't in the list.

You need to store some abstraction of the tags in an array, and that's jQuery's UUIDs. You could write your own UUID functionality, but ideally you just leverage the UUID functionality already built-in to JQuery for both code-size and quality reasons. You could ask JQuery to attach a UUID to the tag implicitly by calling $.data(tag, 'irrelevant', 1) and then check tag[jQuery.expando] to get its UUID, and finally use that in the list... but that's a bit of a hack. Really what would be ideal is to have the following exposed in the public API:

$.getUuid(tag): Checks for and creates a UUID if none exists - ideally the method is factored out of $.data() and creates or fetches the uuid for the tag passed in.

So, is there a reason this isn't factored out into its own method in jQuery? Is this harmful in some way? Was it just never something that seemed useful?

I should note that I've actually factored it out in the version of jQuery we're using, and it's very helpful. But perhaps there's an underlying risk I'm not hitting in my usage. I'm also aware of a plugin that sort-of accomplishes this, but it's a bit broken - and having 2 codepaths to perform the same UUID functionality is both a bit wasteful and a bit brittle.


I think the obvious answer here is that jQuery built their uuid for internal use and hasn't seen a great reason or great demand to bother making it publicly consumable. That doesn't mean reasons don't exist, just that they haven't seemed important enough for it to make it to the top of the list of things to work on.

Monotomically increasing counters to be used as unique IDs are pretty trivial to implement and I've used one many times. I didn't feel like I needed class library support for it to do so.

I think your fear of memory leaks because you keep object references around is a bit overblown. First off, it's only a memory leak if you get rid of the object and forget to get rid of some reference to it. That's just a general rule in garbage collected languages that you have to "know" where you're keeping references to objects that you may get rid of and clean up those references when you intend for the object to be freed.

Second, it's only a meaningful memory leak if you do the same thing a lot of times per page or if the object is very, very large. They all get cleaned up when you go onto the next page so it's not like it's something that accumulates forever unless you never leave that browser page and do the same thing over and over which involves removed objects, but references that aren't removed.

Third, jQuery's .data() mechanism attempts to solve a lot of this for you when using DOM objects.

Fourth, in your contrived example, this does not create a memory leak unless you don't clean up your array of icons in state 2 when it's no longer valid or no longer being used. If you clean it up, then there's no problem with storing a direct DOM reference in that array. If you don't clean up the array, then even the array itself is a memory leak, even if it has abstract uuids in it instead of DOM references. Using abstract references is just a lot more work than needed most of the time.

Again, even if you get it to leak, the leaks are only important if the page has a long life and you are repeatedly creating and releasing objects, but not clearing all references to them in a way that the references accumulate over time and doing this enough that the memory leak they cause is meaningful. I keep references to DOM objects in JS variables all the time. I am just careful to make sure that I null them out when I no longer need them so I know that the DOM object can be freed sometime down the road.


This was submitted to the jQuery team and rejected.

However, you can maintain a list of tags that delegates garbage collection to jQuery like so:

http://jsfiddle.net/b9chris/Un2mH/

The essential code being:

sets[oldIndex] = sets[oldIndex].not(this);
sets[index] = sets[index].add(this);

Although this creates a separate memory burden - these methods do more than just add a tag to an array, they also maintain a stack of previous states of this collection (.pushStack() is called internally). If the page is long-lived with a lot of user actions, the collections will grow without bound. To prevent this you can hack the objects to delete the stack:

sets[oldIndex] = sets[oldIndex].not(this);
sets[oldIndex].prevObject = null;
sets[index] = sets[index].add(this);
sets[index].prevObject = null;

A waste of some CPU cycles but clean enough.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜