引擎盖下JQuery使用“UUID”的地图(只是一个维护为jQuery.uuid
的计数器)来解决浏览器在DOM中添加属性时出现的众所周知的内存泄漏问题来自Javascript。代替这样做,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功能既有点浪费又有点脆弱。
答案 0 :(得分:4)
我认为这里显而易见的答案是,jQuery为内部使用构建了他们的uuid,并没有看到一个很好的理由或很大的需求来打扰它的公共消费品。这并不意味着原因不存在,只是因为它们似乎没有足够的重要性使它成为最重要的事物清单。
单调增加用作唯一ID的计数器实现起来非常简单,而且我已经多次使用过。我不觉得我需要类库支持才能这样做。
我认为你对内存泄漏的恐惧,因为你保持对象参考周围有点过分了。首先,如果你摆脱了对象并忘记摆脱对它的一些引用,它只是一个内存泄漏。这只是在你要“知道”你在哪里保存引用,你可以摆脱的对象,当你打算为对象被释放清理这些引用垃圾回收语言的一般规则。
其次,如果你每页多次做同样的事情或者对象非常非常大,那么它只是一个有意义的内存泄漏。他们都得到清理,当你去到下一个页面,以便它不喜欢它的东西,积累永远除非你永远不离开那个浏览器页面,并做同样的事情一遍又一遍,涉及删除的对象,但不删除引用。< / p>
第三,jQuery的.data()机制试图在使用DOM对象时为你解决很多问题。
第四,在你的设计示例中,这不会造成内存泄漏,除非在状态2不再有效或不再使用时不清理状态2中的图标数组。如果你清理它,那么在该数组中存储直接DOM引用是没有问题的。如果你不清理数组,那么即使数组本身也是内存泄漏,即使它有抽象的uuids而不是DOM引用。使用抽象引用比大多数时候需要的工作多得多。
再有,就算你得到它的泄漏,泄漏是唯一重要的,如果页面有很长的寿命和你重复创建和释放对象,但不清除的方式对他们的所有引用的参考文献随着时间累积并且这样做足以使它们引起的内存泄漏是有意义的。我一直在JS变量中引用DOM对象。我只是小心翼翼地确保在我不再需要它时将它们清空,所以我知道DOM对象可以在不久的将来被释放。
答案 1 :(得分:0)
这是提交给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周期,但足够干净。