В поисках более быстрого $. (': Data (key)') - PullRequest
2 голосов
/ 05 января 2011

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

el.data('lalala', my_data);

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

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

el.data('lalala') != null;

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

$(':data(lalala)').each(...);

Все было замечательно, покаЯ пришел к ситуации, когда мне нужно выполнить этот код 50 раз - это очень медленно !Выполнение на моей странице занимает около 8 секунд с 3640 элементами DOM

var x, t = (new Date).getTime();
for (n=0; n < 50; n++) {
  jQuery(':data(lalala)').each(function() {
    x++;
  });
};
console.log(((new Date).getTime()-t)/1000);

Так как мне не нужен RegExp в качестве параметра селектора :data, я попытался заменить его на

var x, t = (new Date).getTime();
for (n=0; n < 50; n++) {
  jQuery('*').each(function() {
    if ($(this).data('lalala'))
      x++;
  });
};
console.log(((new Date).getTime()-t)/1000);

Этот код быстрее (5 секунд), но я хочу получить больше.

Q Есть ли более быстрый способ получить все элементы с помощью этого ключа данных?

На самом деле, я могу сохранить массив со всеми необходимыми мне элементами, так как я выполняю .data('key') в моем модуле.Лучше проверять 100 элементов с желаемым .data('lalala'), чем проверять 3640:)

Таким образом, решение будет похоже на

for (i in elements) {
  el = elements[i];
  ....

Но иногда элементы удаляются со страницы (используя jQuery * 1036).*).Оба решения, описанные выше [$(':data(lalala)') solution и if ($(this).data('lalala'))], будут пропускать удаленные элементы (как мне нужно), в то время как решение с массивом будет по-прежнему указывать на удаленный элемент (на самом деле, элемент не будет действительно удален - он будет толькобыть удален из дерева DOM - потому что мой массив все еще будет иметь ссылку).

Я обнаружил, что .remove() также удаляет данные из узла, поэтому мое решение изменится на

var toRemove = [];

for (vari in elements) {
  var el = elements[i];
  if ($(el).data('lalala'))
    ....
  else
    toRemove.push(i);
};

for (var ii in toRemove)
  elements.splice(toRemove[ii], 1); // remove element from array

Это решение в 100 раз быстрее!

Q Будет ли сборщик мусора освобождать память, занятую элементами DOM при удалении из этого массива?

Помните, на элементы ссылалисьВ дереве DOM мы создали новую ссылку в нашем массиве, затем удалили с помощью .remove(), а затем удалили из массива.

Есть ли лучший способ сделать это?

Ответы [ 2 ]

2 голосов
/ 05 января 2011

Есть ли более быстрый способ получить все элементы с помощью этого ключа данных?

Конечно !, зацикливайте хранилище данных напрямую, а не через элемент, например, если вы хотите считать:

var x=0;
for(var key in $.cache) { 
  if(typeof $.cache[key]["lalala"] != "undefined") x++; 
}

Это будет почти мгновенно, поскольку элементы имеют запись в $.cache, только если у них есть данные и / или события, и нет обход DOM.

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

0 голосов
/ 05 января 2011

Начиная с версии 1.4.3 jQuery поддерживает атрибут данных HTML5.
Это означает: если вы установите HTML-атрибут data-lalala, вы также можете получить доступ к этим атрибутам, используя element.data('lalala'). Это должно быть намного быстрее, потому что вы используете
родной атрибут-селектор $('*[data-lalala]') вместо некоторых обходных путей.

Итак, вы должны использовать:

el.attr('data-lalala', my_data);

вместо

el.data('lalala', my_data);

Примечание. Поскольку эти атрибуты данных допускают только строки, вам необходимо хранить объекты в виде строкового JSON, если вам нужно работать с объектами.

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