Делает ли jQuery какое-либо кэширование "селекторов"?


например, будет ли первый фрагмент кода выполнять полный поиск дважды, или он достаточно умен, чтобы кэшировать результаты, если никаких изменений DOM не произошло?

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

и

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

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

если селектор более сложный, я могу себе представить, что это нетривиальный удар.

14 53

14 ответов:

jQuery этого не делает, но есть возможность назначить переменные в вашем выражении, а затем использовать их повторно в последующих выражениях. Итак, кэш-если ваш пример ...

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

недостатком является то, что это делает код немного fuglier и трудно grok.

всегда кэшировать ваши выборы!

расточительно постоянно звонить $( selector ) снова и снова с тем же селектором.

или почти всегда... Как правило, вы должны хранить кэшированную копию объекта jQuery в локальной переменной, если вы не ожидаете, что она изменилась или вам это нужно только один раз.

var element = $("#someid");

element.click( function() {

  // no need to re-select #someid since we cached it
  element.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]);

NB, это сломает вашу реализацию MooTools или любую другую библиотеку, которая использует $$ нотации.

Я не думаю, что это так (хотя мне не хочется читать три с половиной тысячи строк JavaScript на данный момент, чтобы узнать наверняка).

однако то, что вы делаете, не требует нескольких селекторов - это должно работать:

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

подобно вашему подходу$$, я создал функцию (с тем же именем), которая использует шаблон запоминания для сохранения глобальной чистоты, а также учитывает второй параметр контекста... любить."($$ class", "#context"). Это необходимо, если вы используете цепную функцию find (), которая происходит после возврата$$; таким образом, она не будет кэшироваться отдельно, если вы сначала не кэшируете объект контекста. Я также добавил логический параметр в конец (2-й или 3-й параметр в зависимости от того, используете ли вы контекст), чтобы заставить его возвращайся в дом.

код:

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 в своем jQuery Internals talk в jQuery Camp 2008 упоминает о некоторых браузерах, поддерживающих события, которые запускаются при изменении DOM. В таких случаях результаты Selctor могут быть кэшированы.

есть хороший плагин там называется jQache что делает именно это. После установки плагина, я обычно делаю это:

var $$ = $.м;

и только потом

$$("#navbar .заголовок.)"hide ();

лучшая часть всего этого заключается в том, что вы также можете очистить свой кэш, когда это необходимо, если вы делаете динамические вещи, например:

$$("#navbar .заголовок", правда).прятаться(); // очищает кэш и скрывает новую (только что найденную ) #navbar .заголовок

и

$$.clear (); / / очищает кэш полностью

jQuery Sizzle автоматически кэширует последние функции, созданные из селекторов, чтобы найти элементы DOM. Однако сами элементы не кэшируются.

кроме того, Sizzle поддерживает кэш самых последних скомпилированных функций. Кэш имеет максимальный размер (который можно настроить, но имеет значение по умолчанию), поэтому вы не получаете ошибки из памяти при использовании большого количества различных селекторов.

jsPerf сегодня не работает, но в этой статье предполагает, что выигрыш в производительности от кэширования селекторов jQuery будет минимальным.

enter image description here

Это может быть кэширование браузера. Тестируемый селектор был только одним идентификатором. Больше тестов должно быть сделано для более сложных селекторов и различных структур страниц...

$.selectorCache () полезно:

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

Gist embed:

<script src="https://gist.github.com/jduhls/ceb7c5fdf2ae1fd2d613e1bab160e296.js"></script>

Проверьте, помогает ли это https://plugins.jquery.com/cache/

наткнулся на это в рамках нашего регулярного проекта