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>
【讨论】:
在几乎所有语言中使用变量a
和b
或x
和y
通常不好,因为它们是常用的内部变量名称,但这是一个插件的良好开端
要到达这里: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
要点嵌入:
<script src="https://gist.github.com/jduhls/ceb7c5fdf2ae1fd2d613e1bab160e296.js"></script>
【讨论】:
【参考方案14】:检查这是否有帮助 https://plugins.jquery.com/cache/
在我们的常规项目中遇到了这个
【讨论】:
以上是关于jQuery 是不是对“选择器”进行任何类型的缓存?的主要内容,如果未能解决你的问题,请参考以下文章