jQuery 是不是对“选择器”进行任何类型的缓存?

Posted

技术标签:

【中文标题】jQuery 是不是对“选择器”进行任何类型的缓存?【英文标题】:Does jQuery do any kind of caching of "selectors"?jQuery 是否对“选择器”进行任何类型的缓存? 【发布时间】:2010-09-22 10:53:17 【问题描述】:

例如,第一段代码是否会执行两次完整搜索,或者如果没有发生 DOM 更改,它是否足够聪明地缓存结果?

if ($("#navbar .heading").text() > "") 
  $("#navbar .heading").hide();

var $heading = $("#navbar .heading");

if ($heading.text() > "") 
  $heading.hide();

如果选择器更复杂,我可以想象这是一个不平凡的命中。

【问题讨论】:

在我看来,它应该缓存唯一的选择器,例如 ID。如果有一个允许缓存所有其他选择器的插件也很好。 jQuery 团队在这里指出了这一点。 learn.jquery.com/using-jquery-core/selecting-elements/… 【参考方案1】:

始终缓存您的选择!

用同一个选择器一遍又一遍地调用$( selector )是很浪费的。

或者几乎总是...您通常应该将 jQuery 对象的缓存副本保存在局部变量中,除非您希望它已经更改或者您只需要它一次。

var element = $("#someid");

element.click( function() 

  // no need to re-select #someid since we cached it
  element.hide(); 
);

【讨论】:

关于 element.hide(); 的快速问题。既然它在一个闭包中,那么做 element.hide() 还是 $(this).hide() 更好?我不确定将它包装在 jquery 对象中而不是爬取作用域链花费了多少额外时间。 element.hide() 通常更好,除非您希望闭包在多个元素上工作,因此将其绑定到 $(this)。尽管如果您担心这些事情中的任何一个的“性能”,那么您就会遇到不切实际的优化案例。无论是作用域链,还是$(this),都不会成为任何应用程序的瓶颈。 总是??? jsfiddle.net/0zrtcfp9 我只会在需要时说,并注意变量引用、范围和内存使用情况【参考方案2】:

jQuery 没有,但有可能在表达式中分配给变量,然后在后续表达式中重新使用这些变量。所以,缓存你的例子......

if ((cached = $("#navbar .heading")).text() > "") 
  cached.hide();

缺点是它使代码有点笨拙且难以理解。

【讨论】:

不必这样做,在许多情况下,使用变量将您选择的元素存储在干净命名的组中会更简洁。 我刚刚写了一个轻量级插件,它可以为你缓存选择器,同时保持你的代码干净。 github.com/farzher/jQuery-Selector-Cache 注意:请确保你们在声明变量时使用var关键字,以免它们不必要地被提升到全局范围内。【参考方案3】:

这不是“可以吗?”的问题,而是“可以吗?”,不,它不能 - 自上次运行查询以来,您可能已经向 DOM 添加了额外的匹配元素。这会使缓存的结果过时,并且 jQuery 除了再次运行查询之外没有(明智的)方法可以告诉。

例如:

$('#someid .someclass').show();
$('#someid').append('<div class="someclass">New!</div>');
$('#someid .someclass').hide();

在此示例中,如果查询缓存有任何缓存,则不会隐藏新添加的元素 - 它只会隐藏之前显示的元素。

【讨论】:

它可以检测到调用之间对 dom 的更改并使缓存无效。如果这就是它的设计方式。 听起来对我来说开销更大——我想搜索比监视整个 DOM 更容易使用快捷方式。但谁知道呢? :) 是的,同意,并不意味着完整的 DOM 扫描,只是意味着如果您限制自己使用 jQuery 更改 DOM,您可以检测到更改。【参考方案4】:

我刚刚做了一个解决这个问题的方法:

var cache = ;

function $$(s)

    if (cache.hasOwnProperty(s))
    
        return $(cache[s]);
    

    var e = $(s);

    if(e.length > 0)
    
        return $(cache[s] = e);
    


它的工作原理是这样的:

$$('div').each(function() ... );

根据这个简单的检查,据我所知,结果是准确的:

console.log($$('#forms .col.r')[0] === $('#forms .col.r')[0]);

注意,它会破坏您的 MooTools 实现或任何其他使用 $$ 表示法的库。

【讨论】:

为什么如果(e.length > 0)。如果没有选择任何元素,这将返回 undefined。 这样做是为了避免用空数据填充缓存存储。您可以轻松更改逻辑。上面的示例并不意味着按原样使用,而是根据您的应用需求采用。您可能还会注意到它并不支持原始 jQuery(); 支持的所有参数。【参考方案5】:

我认为不会(尽管目前我不想通过阅读三千五行 javascript 来确定答案)。

但是,您所做的不需要多个选择器 - 这应该可以:

$("#navbar .heading:not(:empty)").hide();

【讨论】:

【参考方案6】:

与您的 $$ 方法类似,我创建了一个函数(同名),该函数使用记忆模式来保持全局更清晰,并且还考虑了第二个上下文参数......比如 $$(".class", " #语境”)。如果您使用返回 $$ 后发生的链式函数 find(),则需要这样做;因此它不会被单独缓存,除非您先缓存上下文对象。我还在末尾添加了布尔参数(第二个或第三个参数取决于您是否使用上下文)以强制它返回到 DOM。

代码:

function $$(a, b, c)
    var key;
    if(c)
        key = a + "," + b;
        if(!this.hasOwnProperty(key) || c)
            this[key] = $(a, b);
                
    
    else if(b)
        if(typeof b == "boolean")  
            key = a;  
            if(!this.hasOwnProperty(key) || b)
                this[key] = $(a);
            
        
        else
            key = a + "," + b;
            this[key] = $(a, b);   
                    
    
    else
        key = a;
        if(!this.hasOwnProperty(key))
            this[key] = $(a);
         
    
    return this[key]; 

用法:

<div class="test">a</div>
<div id="container">
    <div class="test">b</div>
</div>​

<script>
  $$(".test").append("1"); //default behavior
  $$(".test", "#container").append("2"); //contextual 
  $$(".test", "#container").append("3"); //uses cache
  $$(".test", "#container", true).append("4"); //forces back to the dome
​
</script>

【讨论】:

在几乎所有语言中使用变量abxy 通常不好,因为它们是常用的内部变量名称,但这是一个插件的良好开端 要到达这里:if(!this.hasOwnProperty(key) || b) b 必须始终是 true,因为你先是 else if(b)(真实)然后是 if(typeof b == "boolean"),这保证它是一个布尔值。唯一真实的布尔值是true this 在 IE 和早期版本中也将是 window 没有 hasOwnProperty 因此你必须 Object.prototype.hasOwnProperty.call(this,key)【参考方案7】:

我不相信 jquery 对选择器进行任何缓存,而是依靠下面的 xpath/javascript 来处理它。话虽如此,您可以在选择器中使用许多优化。以下是一些涵盖一些基础知识的文章:

Optimizing jQuery selector performance Performance analysis of selectors

【讨论】:

正要修改,但两个链接都坏了:-(【参考方案8】:

这个 $$() 工作正常 - 在任何情况下都应该返回一个有效的 jQuery 对象,并且永远不会未定义。

小心!它应该/不能与动态变化的选择器一起使用,例如。通过添加与选择器匹配的节点或使用伪类。

function $$(selector) 
  return cache.hasOwnProperty(selector) 
    ? cache[selector] 
    : cache[selector] = $(selector); 
;

当然,$$ 可以是任何函数名称。

【讨论】:

【参考方案9】:

John Resig 在 2008 年 jQuery Camp 的 Jquery Internals 演讲中确实提到了一些浏览器支持在 DOM 被修改时触发的事件。对于这种情况,可以缓存 Selctor 结果。

【讨论】:

【参考方案10】:

有一个很好的插件叫做jQache 可以做到这一点。 安装插件后,我通常会这样做:

var $$ = $.q;

然后就

$$("#navbar .heading").hide();

所有这一切中最好的部分是,如果您正在执行动态操作,您还可以在需要时刷新缓存,例如:

$$("#navbar .heading", true).hide(); // 刷新缓存并隐藏新的(新发现的)#navbar .heading

还有

$$.clear(); // 完全清除缓存

【讨论】:

不错! $$("#navbar .heading", true) 是否也重新填充缓存? 是的!它立即返回新结果并将其缓存。查看插件的站点——它有更高级的东西,我什至没有使用过,比如选择器列表(这样你就可以对它们进行分组并只清除特定的种类)等等——但是进入它真的很简单而且我发现我真的不需要更高级的东西:)【参考方案11】:

jsPerf 今天下降了,但this article 表明缓存 jQuery 选择器的性能提升将是最小的。

这可能只是浏览器缓存。测试的选择器只有一个 id。对于更复杂的选择器和不同的页面结构应该做更多的测试......

【讨论】:

【参考方案12】:

jQuery Sizzle 会自动缓存最近从选择器创建的函数,以便查找 DOM 元素。但是元素本身并没有被缓存。

此外,Sizzle 还保留了最近编译的函数的缓存。缓存有一个最大大小(可以调整,但有一个默认值),因此在使用许多不同的选择器时不会出现内存不足的错误。

【讨论】:

【参考方案13】:

$.selectorCache() 很有用:

https://gist.github.com/jduhls/ceb7c5fdf2ae1fd2d613e1bab160e296

要点嵌入:

&lt;script src="https://gist.github.com/jduhls/ceb7c5fdf2ae1fd2d613e1bab160e296.js"&gt;&lt;/script&gt;

【讨论】:

【参考方案14】:

检查这是否有帮助 https://plugins.jquery.com/cache/

在我们的常规项目中遇到了这个

【讨论】:

以上是关于jQuery 是不是对“选择器”进行任何类型的缓存?的主要内容,如果未能解决你的问题,请参考以下文章

使用 jquery 选择器选择连续的 ID - 是不是有任何简写?

jquery中有哪几种类型的选择器?

Jquery 选择器大全

Jquery 选择器大全

jquery中的缓存与链式选择器?

jquery标签选择器怎么循环