例如,第一段代码是否会执行两次完整搜索,或者如果没有发生 DOM 更改,它是否足够聪明地缓存结果?
if ($("#navbar .heading").text() > "") {
$("#navbar .heading").hide();
}
和
var $heading = $("#navbar .heading");
if ($heading.text() > "") {
$heading.hide();
}
如果选择器更复杂,我可以想象这是一个不平凡的打击。
例如,第一段代码是否会执行两次完整搜索,或者如果没有发生 DOM 更改,它是否足够聪明地缓存结果?
if ($("#navbar .heading").text() > "") {
$("#navbar .heading").hide();
}
和
var $heading = $("#navbar .heading");
if ($heading.text() > "") {
$heading.hide();
}
如果选择器更复杂,我可以想象这是一个不平凡的打击。
用同一个选择器不断地$( selector )一遍又一遍地调用是很浪费的。
或者几乎总是......您通常应该将 jQuery 对象的缓存副本保存在局部变量中,除非您希望它已经更改或者您只需要它一次。
var element = $("#someid");
element.click( function() {
// no need to re-select #someid since we cached it
element.hide();
});
jQuery 没有,但有可能在表达式中分配给变量,然后在后续表达式中重新使用这些变量。所以,缓存你的例子......
if ((cached = $("#navbar .heading")).text() > "") {
cached.hide();
}
缺点是它使代码有点笨拙且难以理解。
这与其说是“可以吗?”,而在于“可以吗?”,不,它不能 - 自上次运行查询以来,您可能已经向 DOM 添加了额外的匹配元素。这会使缓存的结果过时,并且 jQuery 除了再次运行查询之外没有(明智的)方法可以告诉。
例如:
$('#someid .someclass').show();
$('#someid').append('<div class="someclass">New!</div>');
$('#someid .someclass').hide();
在这个例子中,如果有任何查询缓存,新添加的元素不会被隐藏——它只会隐藏之前显示的元素。
我刚刚做了一个解决这个问题的方法:
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 实现或任何其他使用$$符号的库。
我不认为它确实如此(尽管我现在不想通过阅读三千五行 JavaScript 来确定答案)。
但是,您所做的不需要多个选择器 - 这应该有效:
$("#navbar .heading:not(:empty)").hide();
与您的 $$ 方法类似,我创建了一个函数(同名),它使用记忆模式来保持全局清洁,并且还考虑了第二个上下文参数......比如 $$(".class", "#context" )。如果您使用返回 $$ 后发生的链式函数 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>
我不相信 jquery 对选择器进行任何缓存,而是依靠下面的 xpath/javascript 来处理它。话虽如此,您可以在选择器中使用许多优化。以下是一些涵盖一些基础知识的文章:
这 $$() 工作正常 - 在任何情况下都应该返回一个有效的 jQuery 对象,并且永远不会未定义。
小心它!它应该/不能与动态变化的选择器一起使用,例如。通过附加与选择器匹配的节点或使用伪类。
function $$(selector) {
return cache.hasOwnProperty(selector)
? cache[selector]
: cache[selector] = $(selector);
};
当然,$$ 可以是任何函数名称。
John Resig 在 2008 年 jQuery Camp 的 Jquery Internals 演讲中确实提到了一些浏览器支持在 DOM 被修改时触发的事件。对于这种情况,可以缓存 Selctor 结果。
有一个很好的插件叫做jQache可以做到这一点。安装插件后,我通常会这样做:
变量 $$ = $.q;
然后就
$$("#navbar .heading").hide();
所有这一切中最好的部分是,如果您正在做动态的事情,您还可以在需要时刷新缓存,例如:
$$("#navbar .heading", true).hide(); // 刷新缓存并隐藏新的(新发现的)#navbar .heading
和
$$.clear(); // 完全清除缓存
jsPerf 今天停产了,但是这篇文章表明缓存 jQuery 选择器带来的性能提升是微乎其微的。

这可能只是浏览器缓存。测试的选择器只有一个 id。应该对更复杂的选择器和不同的页面结构进行更多的测试......
jQuery Sizzle会自动缓存最近从选择器创建的函数,以便查找 DOM 元素。但是,元素本身不会被缓存。
此外,Sizzle 维护最近编译的函数的缓存。缓存有一个最大大小(可以调整但有一个默认值),因此在使用许多不同的选择器时不会出现内存不足的错误。
$.selectorCache() 很有用:
https://gist.github.com/jduhls/ceb7c5fdf2ae1fd2d613e1bab160e296
要点嵌入:
<script src="https://gist.github.com/jduhls/ceb7c5fdf2ae1fd2d613e1bab160e296.js"></script>
检查这是否有帮助https://plugins.jquery.com/cache/
作为我们常规项目的一部分遇到这个