jQuery .remove()vs Node.removeChild()和外部映射到DOM节点

tne*_*tne 4 javascript jquery dom

jQuery的jQuery API文档.remove()提到:

除了元素本身之外,还删除了与元素关联的所有绑定事件和jQuery数据.

我认为"绑定事件"在这里意味着"事件处理程序"; 类似的文档.empty()说:

为了避免内存泄漏,jQuery在删除元素本身之前从子元素中删除了其他构造,如数据和事件处理程序.

如果使用这些功能并使用Node.removeChild()(或ChildNode.remove())代替,它听起来就像会发生泄漏.

对现代浏览器来说这是真的吗?

  • 如果是这样,为什么删除节点后不能收集属性和事件处理程序?
  • 如果没有,我们还需要使用.data()吗?检索HTML5 data-属性是否合适?

jQuery.data()(低级功能)的文档说:

jQuery.data()方法允许我们以一种不受循环引用安全的方式将任何类型的数据附加到DOM元素,从而避免内存泄漏.jQuery确保在通过jQuery方法删除DOM元素时以及当用户离开页面时删除数据.

这听起来很像是旧的IE DOM/JS圆形泄漏模式的解决方案,AFAIK在今天的所有浏览器中都得到了解决.

但是,jQuery src/data.js代码(快照)中的注释说:

为2014年的WeakMap实施升级提供明确的途径

这表明将来仍然考虑使用带有地图的单独数据存储来严格存储与DOM外部的DOM节点严格关联的数据的想法.

这只是为了向后兼容,还是更多呢?

提供给像这样的其他问题的答案似乎也暗示外部映射的唯一原因是避免DOM对象和JS对象之间的循环引用,我认为这在这个问题的上下文中是无关紧要的(除非我弄错了).

此外,我已经看到插件现在直接在相关的DOM节点上设置属性(例如selectize.js),它似乎并没有打扰任何人.这是一个好的做法吗?它看起来确实如此,因为它可以很容易地删除整个DOM树.无需将其拆除,无需清理任何外部数据存储,只需将其从父节点分离,丢失引用,并让垃圾收集器执行其操作.

进一步说明,背景和问题的理由:

这种功能对于管理视图的框架(例如Durandal)尤其有用,这些框架经常需要替换在其体系结构中表示所述视图的整个树.虽然他们中的大多数肯定明确支持jQuery,但这个解决方案根本不能扩展.还必须清除使用类似数据存储的每个组件.在Durandal的情况下,似乎它们(至少在一次出现时,对话框插件 - 快照)依赖于Knockout .removeNode()(快照)实用程序函数,后者又使用jQuery的内部cleanData()函数.那就是,恕我直言,这是一个可怕的特殊外壳的一个主要例子(我不确定它现在是否正常,如果jQuery用于noConflict模式,它在大多数AMD设置中).

这就是为什么我想知道我是否可以安全地忽略所有这些,或者我们是否必须等待Web Components才能重新获得我们久已失去的理智.

coo*_*ter 7

"如果不使用这些函数并使用Node.removeChild()(或ChildNode.remove()),它听起来就会发生泄漏.

对现代浏览器来说这是真的吗?

如果是这样,为什么删除节点后不能收集属性和事件处理程序呢?"

绝对.与元素关联的数据(包括事件处理程序)保存在一个全局对象中jQuery.cache,并通过序列号jQuery将其删除元素.

当jQuery删除元素时,它会抓取序列号,查找条目jQuery.cache,手动删除数据,然后删除元素.

在没有jQuery的情况下销毁元素,您销毁序列号以及缓存中元素条目的唯一关联.垃圾收集器不知道jQuery.cache对象的用途,因此无法对已删除的节点的条目进行垃圾收集.它只是将其视为可能在将来使用的数据的强大参考.


虽然对于像IE6和IE7这样的旧浏览器来说这是一个非常有用的方法,它有严重的内存泄漏问题,但现代工具具有出色的垃圾收集器,可以可靠地找到JavaScript和DOM之间的循环引用.你可以通过对象属性和闭包获得一些非常讨厌的循环引用,GC会找到它们,所以这些浏览器真的不用担心.

但是,由于jQuery以它的方式保存元素数据,因此我们现在必须非常小心使用jQuery来避免基于jQuery的泄漏.这意味着永远不要使用本机方法来删除元素.始终使用jQuery方法,以便jQuery可以执行其强制数据清理.


"此外,我已经看到插件现在直接在相关的DOM节点上设置属性(例如selectize.js),它似乎并没有打扰任何人.这是一个好的做法吗?"

我认为这是大部分时间.如果数据只是原始数据类型,那么就没有机会对函数和对象进行任何类型的循环引用.而且,即使有循环引用,现代浏览器也能很好地处理这个问题.旧浏览器(尤其是IE),不是那么多.


"这就是为什么我很想知道我是否能够安全地忽略所有这一切,或者我们是否必须等待Web Components才能重新获得我们久已失去的理智."

我们不能忽视在销毁节点时使用jQuery特定方法的需要.关于外部框架的观点是一个很好的观点.如果它们不是专门针对jQuery构建的,那么可能会出现问题.

你提到jQuery $.noConflict,这是另一个好点.这很容易允许"安全"加载其他框架/库,这可能会覆盖全局$.这打开了泄漏IMO的大门.

AFAIK,$.noConflict也可以加载多个版本的jQuery.我不知道是否有单独的缓存,但我会这么认为.如果是这样的话,我会想象我们会遇到同样的问题.


如果jQuery确实将在未来使用WeakMaps作为您引用的评论表明,这将是一件好事并且是明智之举.它只会在支持WeakMaps的浏览器中提供帮助,但它总比没有好.


"如果没有,我们还需要使用.data()吗?检索HTML5数据属性是否合适?"

只是想解决第二个问题.有些人认为.data()应该始终使用HTML5 data-属性.我没有因为使用.data()那将导入数据jQuery.cache,所以有更多的内存可能泄漏.

我可以在一些狭窄的情况下看到它,但不是大多数数据.即使没有泄漏,也不需要将大部分data-存储在两个地方.它增加了内存使用而没有任何好处.仅.attr()用于存储为data-属性的大多数简单数据.