Делает ли jQuery кеширование "селекторов"? - PullRequest
54 голосов
/ 15 ноября 2008

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

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

и

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

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

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

Ответы [ 14 ]

28 голосов
/ 15 апреля 2012

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

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

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

var element = $("#someid");

element.click( function() {

  // no need to re-select #someid since we cached it
  element.hide(); 
});
16 голосов
/ 15 ноября 2008

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

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

Недостатком является то, что он делает код немного сложнее и сложнее его взломать.

14 голосов
/ 16 ноября 2008

Это не столько вопрос «не так ли?», Но «может ли это?», И нет, не может - возможно, вы добавили дополнительные подходящие элементы в DOM с момента последнего запуска запроса. Это сделало бы кэшированный результат устаревшим, и у jQuery не было бы (разумного) способа сообщить что-либо, кроме повторного выполнения запроса.

Например:

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

В этом примере вновь добавленный элемент не будет скрыт, если будет какое-либо кэширование запроса - он будет скрывать только те элементы, которые были обнаружены ранее.

12 голосов
/ 14 октября 2011

Я только что сделал метод для решения этой проблемы:

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 или любую другую библиотеку, которая использует $$ запись.

9 голосов
/ 15 ноября 2008

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

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

$("#navbar .heading:not(:empty)").hide();
6 голосов
/ 20 июля 2012

Подобно вашему подходу $$, я создал функцию (с тем же именем), которая использует шаблон запоминания, чтобы поддерживать глобальную чистоту, а также учитывает второй параметр контекста ... как $$ (". Class", " #context "). Это необходимо, если вы используете цепочечную функцию find (), которая происходит после возврата $$; таким образом, он не будет кэшироваться один, если вы сначала не кешируете объект контекста. Я также добавил логический параметр в конец (2-й или 3-й параметр в зависимости от того, используете ли вы контекст), чтобы заставить его вернуться к 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>
4 голосов
/ 15 ноября 2008

Я не верю, что jquery выполняет какое-либо кэширование селекторов, вместо этого полагаясь на xpath / javascript, чтобы справиться с этим. При этом существует ряд оптимизаций, которые вы можете использовать в своих селекторах. Вот несколько статей, которые охватывают некоторые основы:

3 голосов
/ 23 августа 2012

Этот $$ () работает нормально - должен возвращать действительный объект jQuery в любом случае, никогда не определенный.

Будь осторожен с этим! Это должно / не может быть с селекторами, которые могут динамически меняться, например. добавляя узлы, соответствующие селектору, или используя псевдоклассы.

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

И, конечно, $$ может быть любым именем функции.

2 голосов
/ 30 октября 2014

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

var $$ = $ .q;

А потом просто

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

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

$$ ("# navbar .heading", true) .hide (); // очищает кеш и скрывает новый (недавно найденный) #navbar .heading

А

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

2 голосов
/ 20 марта 2011

Джон Резиг в своем выступлении по Jquery Internals на jQuery Camp 2008 упоминает о некоторых браузерах, поддерживающих события, которые запускаются при изменении DOM. В таких случаях результаты Selctor могут быть кэшированы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...