是否有jQuery函数对垃圾收集的影响?

时间:2015-04-10 19:53:38

标签: jquery

这个问题是关于jQuery函数如何保存HTML元素,以及是否可能对垃圾收集产生影响。

考虑以下两个功能,显示或隐藏某个< div> HTML页面中的元素。

function showError() { $("div#error").show(); }
function hideError() { $("div#error").hide(); }

这两个函数总是调用jQuery来查找< div> DOM树中的元素;它们可以被重构以消除jQuery函数的开销,因此:

var divError = $("div#error");
function showError() { divError.show(); }
function hideError() { divError.hide(); }

但在这种情况下,divError变量在全局范围内被放宽;我们可以通过一个函数来实现一些技巧:

var showError, hideError;
(function() {
  var divError = $("div#error");
  showError = function() { divError.show(); }
  hideError = function() { divError.hide(); }
})();

在所有这些情况下,对垃圾收集的影响是什么?将调用jQuery函数的结果浮动到全局范围是否有问题?

尝试最小化对jQuery函数的调用是一个很好的规则吗?是应该遵循还是避免这些例子?

如果我用document.getElementById()替换了这些示例中的jQuery,要检索HTML元素,是否也适用相同的问题?

1 个答案:

答案 0 :(得分:2)

垃圾收集

如果您正在做其中的一些,请不要担心。如果单独使用,此处显示的任何一个用户案例都不会对内存使用产生负面影响。

内存占用

在大型循环中完成后,这些将开始产生潜在的影响。 Each time a function object is created, it can take up to 754 bytes of memory。如果您创建了许多这些内容,例如1000,则可能会短暂地占用1MB内存,具体取决于浏览器,这可以忽略不计。 10,000变得更糟(~10MB),100,000(~100MB)变得麻烦,1,000,000(~1GB)可能会开始导致一些严重的问题,取决于客户端以一分钟的UI锁定形式。

范围

当对象未保留在当前执行上下文中时,垃圾收集器将成为先前情况的一个因素。每个执行上下文都有一个词法和可变环境。一旦当前执行上下文失去范围,变量环境就有资格进行垃圾收集。但需要注意的是,符合条件的仅仅意味着它会在某个时间发生并且不会对何时做出承诺。

为了减少不断增长的内存占用,确保实现函数的执行上下文以尽快丢失范围将确保垃圾收集器尽可能快地收集选项。同样,收集的选项可能在一段时间内无法实现。

<强>实施

所有这些都是关闭变量的,所以一旦它们的引用消失了,它们将来可以在垃圾收集器方便的时候收集它们。

性能

除此之外,如果单独使用,调用jQuery函数的问题应该不重要。唯一一次重复查询成为一个问题是当你有超过大约10,000个DOM元素时,你可能已经有其他问题;当你要重复数千次并想避免毫秒堆积时。优化总共不到10毫秒的任何事情都可能是微优化。 10-100是自由裁量的,绝对有100多个。

此外,只要id访问元素,就可以通过字典(哈希表)查找直接访问它,即O(1)。这意味着您的DOM不需要完全解析。然而,情况可能并非总是如此,所以我认为我们不能简单地停在那里。

所以如果只使用一次,那么你的第一个场景就没有错了(这里不需要使用div,id是O(1)查找)。

function showError() { $("#error").show(); }
function hideError() { $("#error").hide(); }

但是,如果由于某种原因,id的字符串是一个类选择器,并且这些是在循环中以某种方式大量完成的,那么你需要确保函数定义的作用域为循环,并且缓存元素选择器(缓存本身引入了一个有趣的侧面案例,其中缓存的元素集实际上可能不匹配动态页面中类选择器之类的页面集 - 但这是一个边缘情况)。

范围

父作用域非常重要,因为您从未真正想要在全局作用域中执行代码。所以虽然这两个完成同样的事情

var divError = $("div#error");
function showError() { divError.show(); }
function hideError() { divError.hide(); }

var showError, hideError;
(function() {
 var divError = $("div#error");
 showError = function() { divError.show(); }
 hideError = function() { divError.hide(); }
})();

(请注意,因为IIFE中的匿名函数具有由其词汇环境引用的变量环境,因此在该词汇环境符合条件之前,将无法进行垃圾收集)

他们都对范围略有不同。第一个将公开变量divError,而第二个不公开。在狭窄的环境中,这并不重要,因为词汇和变量环境中的冲突不太可能,但在全局命名空间中,这可能会有问题,因为在卸载整个页面之前不会收集词汇环境。这称为polluting the global namespace

<强>替代

最后,整个分析归结为应该是相当微不足道的事情。如果要对此元素具有全局访问权限,请将其存储在已安全使用的全局变量中。由于您使用的是jQuery,因此您只需使用$。

即可
$.errorDiv = $("#error");

当你想要切换它时,只需使用切换:)或隐藏/显示你是否不确定状态或以某种方式调用它显示两次。

$.errorDiv.toggle();
$.errorDiv.show();
$.errorDiv.hide();

我理解,这最后一部分可能不会直接适用,因为这可能是对类似行为的简单再现。