开发者

Seeking for faster $.(':data(key)')

I'm writing an extension to jQuery that adds data to DOM elements using

el.data('lalala', my_data);

and then uses that data to upload elements dynamically.

Each time I get new data from the server I need to update all elements having

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

To get all needed elements I use an extension by James Padolsey:

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

Everything was great until I came to the situation where I need to run that code 50 times - it is very slow! It takes about 8 seconds t开发者_运维知识库o execute on my page with 3640 DOM elements

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);

Since I don't need RegExp as parameter of :data selector I've tried to replace this by

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);

This code is faster (5 sec), but I want get more.

Q Are there any faster way to get all elements with this data key?

In fact, I can keep an array with all elements I need, since I execute .data('key') in my module. Checking 100 elements having the desired .data('lalala') is better then checking 3640 :)

So the solution would be like

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

But sometimes elements are removed from the page (using jQuery .remove()). Both solutions described above [$(':data(lalala)') solution and if ($(this).data('lalala'))] will skip removed items (as I need), while the solution with array will still point to removed element (in fact, the element would not be really deleted - it will only be deleted from the DOM tree - because my array will still have a reference).

I found that .remove() also removes data from the node, so my solution will change into

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

This solution is 100 times faster!

Q Will the garbage collector release memory taken by DOM elements when deleted from that array?

Remember, elements have been referenced by DOM tree, we made a new reference in our array, then removed with .remove() and then removed from the array.

Is there a better way to do this?


Are there any faster way to get all elements with this data key?

Sure!, loop over the data store directly instead of via the element, for example if you wanted a count:

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

This will be nearly instant, since elements only have an entry in $.cache if they have data and/or events, and there's no DOM traversal happening.

For the other piece, yes this will skip removed elements, since their cache is cleaned up as well, provided you don't remove them via .innerHTML directly.


Since V1.4.3 jQuery supports the HTML5-data-attribute.
This means: if you set an HTML-attribute data-lalala you can also access these attribute using element.data('lalala') . This should be much faster, because you an use the
native attribute-selector $('*[data-lalala]') instead of some workarounds.

So you have to use:

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

instead of

el.data('lalala', my_data);

Note: As those data-attributes only allow strings, you'll need to store objects as a stringified JSON there, if you need to work with objects.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜