【问题标题】: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();
}

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

【问题讨论】:

标签: jquery jquery-selectors


【解决方案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 来处理它。话虽如此,您可以在选择器中使用许多优化。以下是一些涵盖一些基础知识的文章:

    【讨论】:

    • 正要修改,但两个链接都坏了:-(
    【解决方案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/

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

              【讨论】:

                猜你喜欢
                • 2011-07-24
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2012-08-29
                • 2013-03-17
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多