为什么 JQuery 不公开其 UUID 功能?

发布于 2024-11-29 02:02:05 字数 1153 浏览 0 评论 0原文

在底层,JQuery 使用“UUID”映射(只是它维护为 jQuery.uuid 的计数器)来解决当您将属性附加到标签时浏览器出现的众所周知的内存泄漏问题。来自 JavaScript 的 DOM。相反,JQuery 使用 $.data(tag, name, value) 将数据存储在以 uuid 为键的映射中(可以通过检查 tag 来确定键) [jQuery.expando])。

虽然 $.data() 非常有用,但有时您希望将数据映射到标签,而不将该数据转储到一个全局存储桶中 - 例如,您希望拥有自己的较小的数据存储桶,检查或循环的长度。

作为一个人为的示例,假设您的图标在单击时会在 4 种状态之一之间旋转。当一个处于状态 2 时,您希望将其添加到处于状态 2 的图标数组中。最明显的方法是将标签添加到数组中;但是这样做会造成内存泄漏。您可以在复选框上调用 $.data() ,但这并不能完全完成您想要做的事情 - 您必须循环遍历所有检查 $ 的复选框。 data() 针对它们来找出哪些在列表中,哪些不在列表中。

您需要在数组中存储一些标签的抽象,这就是 jQuery 的 UUID。您可以编写自己的 UUID 功能,但出于代码大小和质量原因,理想情况下您只需利用 JQuery 中内置的 UUID 功能即可。您可以通过调用 $.data(tag, 'irrelevant', 1) 要求 JQuery 将 UUID 隐式附加到标记,然后检查 tag[jQuery.expando] 以获取它的 UUID,最后在列表中使用它......但这有点麻烦。实际上,理想的做法是在公共 API 中公开以下内容:

$.getUuid(tag):检查并创建 UUID(如果不存在) - 理想情况下,该方法是从 中提取出来的$.data() 并为传入的标签创建或获取 uuid。

那么,是否有原因没有将其分解到 jQuery 中自己的方法中呢?这在某种程度上有害吗?难道它从来都没有什么用处吗?

我应该指出,我实际上已经在我们使用的 jQuery 版本中将其分解出来,并且它非常有帮助。但也许在我的使用中存在一个我没有遇到的潜在风险。我还知道有一个插件可以完成此任务,但它有点损坏 - 并且使用 2 个代码路径来执行相同的 UUID 功能既有点浪费又有点脆弱。

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 you 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

抹茶夏天i‖ 2024-12-06 02:02:05

我认为这里明显的答案是 jQuery 构建了他们的 uuid 供内部使用,并且没有看到一个很好的理由或很大的需求来费心让它公开使用。这并不意味着原因不存在,只是它们似乎还不够重要,不足以使其成为需要处理的事情的首要任务。

用作唯一 ID 的单调递增计数器实现起来非常简单,我已经使用过很多次了。我觉得我不需要类库支持来做到这一点。

我认为你对内存泄漏的恐惧是因为你保留了对象引用,这有点过分了。首先,如果您删除该对象并忘记删除对其的某些引用,那么这只是内存泄漏。这只是垃圾收集语言中的一般规则,您必须“知道”在哪里保存对可以删除的对象的引用,并在您打算释放对象时清理这些引用。

其次,只有当您在每个页面上多次执行相同的操作或者对象非常非常大时,这才是有意义的内存泄漏。当您进入下一页时,它们都会被清理掉,因此它不会永远累积,除非您永远不会离开该浏览器页面并一遍又一遍地执行相同的操作,其中涉及已删除的对象,但未删除的引用。

第三,jQuery 的 .data() 机制尝试在使用 DOM 对象时为您解决很多问题。

第四,在您设计的示例中,这不会造成内存泄漏,除非您在状态 2 中的图标数组不再有效或不再使用时不清理它。如果你清理它,那么在该数组中存储直接 DOM 引用就没有问题了。如果你不清理数组,那么即使数组本身也是内存泄漏,即使它里面有抽象的 uuid 而不是 DOM 引用。大多数时候,使用抽象引用只是比需要的工作多得多。

同样,即使发生泄漏,只有当页面寿命很长并且您重复创建和释放对象,但没有以引用随着时间累积的方式清除对它们的所有引用并执行此操作时,泄漏才很重要足以证明它们引起的内存泄漏是有意义的。我一直在 JS 变量中保留对 DOM 对象的引用。我只是小心地确保当我不再需要它们时将它们清空,这样我就知道 DOM 对象可以在将来的某个时候被释放。

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.

夏有森光若流苏 2024-12-06 02:02:05

这个已提交给 jQuery 团队并被拒绝。

但是,您可以维护一个将垃圾收集委托给 jQuery 的标签列表,如下所示:

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

基本代码是:

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

虽然这会产生单独的内存负担 - 这些方法不仅仅是向数组添加标签,它们还维护此集合的先前状态的堆栈 (.pushStack()是内部调用)。如果页面长期存在并且有大量用户操作,则集合将无限增长。为了防止这种情况,你可以破解对象来删除堆栈:

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

浪费一些 CPU 周期,但足够干净。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文