Осуществляет ли jQuery какое-либо кэширование «селекторов»?

StackOverflow https://stackoverflow.com/questions/291841

  •  08-07-2019
  •  | 
  •  

Вопрос

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

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

и

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

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

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

Это было полезно?

Решение

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

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

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

Другие советы

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

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

Или почти всегда ... Как правило, вы должны хранить кэшированную копию объекта 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]);

Примечание: это сломает вашу реализацию 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); 
};

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

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

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

вар $$ = $.q;

И тогда просто

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

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

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

И

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

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

введите описание изображения здесь

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

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/

натолкнулся на это как часть нашего обычного проекта

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top