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



在底层,JQuery使用"uuid"的映射(只是一个计数器,它维护作为jQuery.uuid),以解决众所周知的内存泄漏问题,浏览器有当你从Javascript的DOM附加属性到标签。代替这样做,JQuery使用$.data(tag, name, value)来存储数据在一个映射键的uid(一个键可以通过检查tag[jQuery.expando]来确定)。

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

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

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

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

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

我应该注意到,我实际上已经在我们使用的jQuery版本中分解了它,它非常有用。但也许在我的使用中存在一个潜在的风险。我也知道有一个插件可以做到这一点,但它有点坏——有两个代码路径来执行相同的UUID功能既有点浪费又有点脆弱。

我认为这里最明显的答案是jQuery构建了它们的uid供内部使用,并没有看到一个很好的理由或巨大的需求来让它公开使用。这并不意味着原因不存在,只是它们似乎还不够重要,不足以让它成为工作清单上的首要任务。

作为唯一id使用的单调递增计数器是非常微不足道的实现,我已经使用了很多次。我不觉得我需要类库的支持来做这件事。

我认为你担心内存泄漏,因为你保持对象引用有点夸张。首先,只有当您删除对象并忘记删除对它的某些引用时,才会造成内存泄漏。这只是垃圾收集语言中的一般规则,你必须"知道"你在哪里保存了你可能要删除的对象的引用,并在你打算释放对象时清理这些引用。

第二,只有在每个页面多次执行相同的操作,或者对象非常非常大的情况下,才会出现有意义的内存泄漏。当你进入下一页时,它们都被清理干净了,所以它不会永远积累起来,除非你永远不会离开那个浏览器页面,一遍又一遍地做同样的事情,这涉及到被删除的对象,但引用没有被删除。

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

第四,在您的人为示例中,这不会造成内存泄漏,除非您在状态2的图标数组不再有效或不再使用时不清理它。如果您清理了它,那么在该数组中存储直接DOM引用就没有问题了。如果不清理数组,那么即使数组本身存在内存泄漏,即使它包含抽象uid而不是DOM引用。在大多数情况下,使用抽象引用会比实际需要做更多的工作。

再次强调,即使出现了泄漏,泄漏也只有在页面具有较长的生命周期,并且您正在重复创建和释放对象,但没有清除对它们的所有引用(这些引用会随着时间的推移而积累),并且这样做足够多,从而导致内存泄漏是有意义的情况下才重要。我一直在JS变量中引用DOM对象。我只是小心地确保在不再需要它们时将它们清空,这样我就知道DOM对象可以在以后的某个时候被释放。

这被提交给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周期,但足够干净。

相关内容

  • 没有找到相关文章