7

我的 Javascript (JS) 代码带来了一些麻烦,因为有时我需要在同一个函数中多次访问相同的 DOM 元素。这里也提供了一些推理。

从性能的角度来看,是创建一次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 循环中进行比较)。

提前致谢。

4

6 回答 6

8

缓存元素总是更好,如果 n 大于 1,缓存元素,或者将操作链接在一起(您可以$('#something').something().somethingelse();大多数jQuery操作执行此操作,因为它们通常返回包装集本身)。顺便说一句,以货币符号开头命名缓存变量已成为一种标准,$因此在后面的代码中很明显您正在对 jQuery 集执行操作。var $content = $('#content');所以你以后会看到很多人这样做$content.find('...');

于 2012-08-07T15:57:29.810 回答
4

二是优越。最重要的是,它更干净。以后,如果你想改变你的选择器,你只需要改变一个地方。否则你需要在N个地方改变它。

其次,它应该表现得更好,尽管用户只会注意到特别重的 dom,或者如果您经常调用该函数。

于 2012-08-07T15:57:04.417 回答
2

如果你从不同的角度来看这个问题,正确的答案是显而易见的。

在第一种情况下,您在其出现的每个地方都复制了选择逻辑。如果更改元素的名称,则必须更改每个出现的位置。这应该是足够的理由不这样做。现在你有两个选择——要么缓存元素的选择器,要么缓存元素本身。使用元素作为对象比使用名称更有意义。

在性能方面,我认为效果可以忽略不计。可能您将能够找到此特定用例的测试结果:缓存 jQuery 对象与总是重新选择它们。如果您有一个大型 DOM 并进行大量查找,性能可能会成为一个问题,但您需要自己查看是否是这种情况。

如果您想准确查看对象占用了多少内存,可以使用Chrome Heap Profiler并在那里进行检查。我不知道其他浏览器是否可以使用类似的工具,并且可能实现在性能上会有很大差异,尤其是在 IE 的情况下,但它可能会满足您的好奇心。

IMO,您应该使用第二个变体,将选择结果存储在一个对象中,与其说是提高性能,不如说是尽可能少地重复逻辑。

至于缓存$(this),我同意Nick Craver 的回答。正如他在那里所说,您还应该尽可能使用链接 - 清理您的代码并解决您的问题。

于 2012-08-07T15:59:29.677 回答
1

你应该看看 http://www.artzstudio.com/2009/04/jquery-performance-rules/

或者

http://addyosmani.com/jqprovenperformance/

于 2012-08-07T15:58:43.820 回答
1

我几乎总是更喜欢缓存 jQuery 对象,但是根据您用于选择器的确切内容,其好处会有很大差异。如果您使用 ids,那么好处远小于使用选择器类型的好处。此外,并非所有选择器都是平等创建的,因此在编写选择器时请记住这一点。

例如: $('table tr td')是一个很差的选择器。尝试使用 context 或 .find() 会产生很大的不同。

我喜欢做的一件事是在我的代码中放置计时器以查看它的效率。

var timer = new Date(); 
// code here
console.log('time to complete: ' + (new Date() - timer));

大多数缓存对象将在不到 2 毫秒的时间内执行,而全新的选择器需要更长的时间,因为您首先必须找到元素,然后执行操作。

于 2015-01-19T18:49:40.077 回答
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)构造函数来节省内存,该构造函数在迭代它们时基本上应该是免费的。

但是,正如人们所说,您只能通过对不同方法进行基准测试来了解针对您的特定情况的最佳方法。即使理论看起来很合理,也很难预测现实;-)。

于 2016-12-06T01:53:13.430 回答