我遇到了一些来自我的Javascript(JS)代码的麻烦,因为我有时需要在同一个函数中多次访问相同的DOM元素。还提供了一些推理here。
从性能的角度来看,创建一个jQuery对象然后缓存它是否更好?或者更好地随意创建相同的jQuery对象? 例如:
function(){
$('selector XXX').doSomething(); //first call
$('selector XXX').doSomething(); //second call
...
$('selector XXX').doSomething(); // n-th call
}
或
function(){
var obj = $('selector XXX');
obj.doSomething(); //first call
obj.doSomething(); //second call
...
obj.doSomething(); // n-th call
}
我认为答案可能取决于“n”的值,因此假设n是“小”数字(例如3),然后是中等数字(例如10),最后是大数字(例如30,就像在for循环中使用对象进行比较一样。)
提前致谢。
答案 0 :(得分:7)
总是更好地缓存元素,如果n大于1,则缓存元素或将操作链接在一起(对于 most <,您可以$('#something').something().somethingelse();
/ em> jQuery操作,因为它们通常返回包装集本身)。顺便说一下,以货币符号$
开头的缓存变量命名已经成为一种标准,因此在代码的后面很明显你正在对jQuery集执行操作。因此,您会看到很多人稍后会var $content = $('#content');
然后$content.find('...');
。
答案 1 :(得分:4)
第二个是优越的。最重要的是,它更清洁。将来,如果要更改选择器,只需将其更改为一个位置即可。否则你需要在N个地方改变它。
其次,它应该表现得更好,尽管用户只会注意到特别沉重的dom,或者你是否经常调用该函数。
答案 2 :(得分:2)
如果从不同的角度看待这个问题,那么正确答案是显而易见的。
在第一种情况下,您在其出现的每个位置重复选择逻辑。如果更改元素的名称,则必须更改每个出现的位置。这应该是不足以做到这一点的理由。现在您有两个选项 - 要么缓存元素的选择器,要么缓存元素本身。使用元素作为对象比使用名称更有意义。
在性能方面,我认为效果可以忽略不计。可能你会找到这个特定用例的测试结果:缓存jQuery对象vs总是重新选择它们。如果你有一个大型的DOM并进行大量的查找,性能可能会成为一个问题,但如果是这种情况,你需要自己查看。
如果您想确切了解对象占用多少内存,可以使用Chrome Heap Profiler并在那里查看。我不知道是否有类似的工具可供其他浏览器使用,可能实现的性能差别很大,特别是在IE的情况下,但它可能会满足您的好奇心。
IMO,你应该使用第二种变体,将选择的结果存储在一个对象中,不是为了提高性能,而是尽可能少地重复逻辑。
至于缓存$(this)
,我同意Nick Craver's answer。正如他在那里所说,你应该尽可能使用链接 - 清理你的代码并解决你的问题。
答案 3 :(得分:1)
答案 4 :(得分:1)
我几乎总是喜欢缓存jQuery对象,但是根据您对选择器使用的确切内容,优势会有很大差异。如果您正在使用ID,那么获益远远小于使用选择器类型时的好处。此外,并非所有选择器都是同等创建的,因此在编写选择器时请记住这一点。
例如:
$('table tr td')
是一个非常差的选择器。尝试使用context或.find(),它会产生很大的不同。
我喜欢做的一件事是在我的代码中放置计时器,看看它的效率如何。
var timer = new Date();
// code here
console.log('time to complete: ' + (new Date() - timer));
大多数缓存的对象将在不到2毫秒的时间内执行,因为首先必须找到该元素,然后执行操作,因为全新的选择器需要更长的时间。
答案 5 :(得分:0)
在JavaScript中,函数通常是短暂的 - 特别是在由浏览器托管时。但是,函数的范围可能比函数更长。例如,当您创建闭包时,就会发生这种情况。如果要阻止jQuery
对象长时间被引用,可以在完成该变量或使用间接创建闭包时将null
分配给引用它的任何变量。例如:
var createHandler = function (someClosedOverValue) {
return function () {
doSomethingWith(someClosedOverValue);
};
}
var blah = function () {
var myObject = jQuery('blah');
// We want to enable the closure to access 'red' but not keep
// myObject alive, so use a special createHandler for it:
var myClosureWithoutAccessToMyObject = createHandler('red');
doSomethingElseWith(myObject, myClosureWithoutAccessToMyObject);
// After this function returns, and assuming doSomethingElseWith() does
// not itself generate additional references to myObject, myObject
// will no longer have any references and be elligible for garbage
// collection.
}
因为jQuery(selector)
可能最终不得不运行昂贵的算法,甚至为了直接浏览器无法处理的复杂表达式而使用DOM树,所以最好缓存返回的对象。此外,正如其他人所提到的,为了代码清晰,最好缓存返回的对象以避免多次键入选择器。即,DRY代码通常比WET代码更容易维护。
但是,每个jQuery对象都有一些开销。因此,将大型jQuery对象存储在全局变量中可能是浪费 - 除非您确实需要对大量这些对象进行操作并仍然将它们视为不同的对象。在这种情况下,您可以通过直接缓存DOM元素的数组并使用jQuery(DOMElement)
构造函数来节省内存,这些构造函数在迭代时基本上应该是免费的。
尽管如人们所说,通过对不同方法进行基准测试,您只能知道针对特定情况的最佳方法。即使理论看起来很合理,也难以预测现实; - )。