【问题标题】:Seeking for faster $.(':data(key)')寻求更快的 $.(':data(key)')
【发布时间】:2011-06-03 18:17:25
【问题描述】:

我正在为 jQuery 编写一个扩展,使用

向 DOM 元素添加数据
el.data('lalala', my_data);

然后使用该数据动态上传元素。

每次我从服务器获取新数据时,我都需要更新所有具有的元素

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

为了获得所有需要的元素,我使用James Padolsey 的扩展:

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

一切都很好,直到我遇到需要运行该代码 50 次的情况 - 它非常慢!使用 3640 个 DOM 元素在我的页面上执行大约需要 8 秒

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 秒),但我想要更多。

有没有更快的方法来使用这个数据键获取所有元素?

事实上,我可以保留一个包含我需要的所有元素的数组,因为我在我的模块中执行.data('key')。检查 100 个具有所需 .data('lalala') 的元素比检查 3640 更好:)

所以解决方案是这样的

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

但有时元素会从页面中删除(使用 jQuery .remove())。上述两种解决方案 [$(':data(lalala)') 解决方案和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-3 个问题。您真正想要回答的问题是哪个?
  • 两个Q。第一个更有趣。

标签: javascript jquery performance jquery-selectors


【解决方案1】:

自 V1.4.3 起,jQuery 支持 HTML5-data-attribute。
这意味着:如果您设置了 HTML 属性 data-lalala,您也可以使用 element.data('lalala') 访问这些属性。这应该快得多,因为您使用了
原生属性选择器$('*[data-lalala]') 而不是一些变通方法。

所以你必须使用:

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

而不是

el.data('lalala', my_data);

注意:由于data-attributes 只允许使用字符串,因此如果您需要使用对象,则需要将对象作为字符串化 JSON 存储在那里。

【讨论】:

  • 我需要将一个函数与一个 DOM 元素关联起来,所以这个解决方案并不是我所需要的。
  • 是的,如果函数名字符串不够,可能会比较复杂。
【解决方案2】:

有没有更快的方法来使用这个数据键获取所有元素?

当然!直接循环数据存储而不是通过元素,例如,如果你想要一个计数:

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

这几乎是即时的,因为元素只有在有数据和/或事件的情况下才会在$.cache 中有一个条目,并且没有 DOM 遍历发生。

对于另一部分,是的,这将跳过已删除的元素,因为它们的缓存也会被清理,前提是您不直接通过 .innerHTML 删除它们。

【讨论】:

  • ... 或者您不使用其他原生 DOM 方法删除它们?
  • 哇!这就是我一直在寻找的地方——真正存储这些数据的地方。
  • 等等,如何检索对象本身 - 谁是特定缓存对象的所有者?我必须遍历 DOM 才能找到它?
  • @PoltoS - 当你找到你想要的那个时,它是$('['+$.expando+'='+key+']') 来获取它的元素...如果你知道它是一个&lt;div&gt; 等,将它添加到选择器中让它更快。
  • @Nick Craver - $('['+$.expando+'='+key+']') 为空。
猜你喜欢
  • 2020-03-21
  • 1970-01-01
  • 1970-01-01
  • 2010-12-17
  • 2010-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-09
相关资源
最近更新 更多