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

Posted by PoltoS on Stack Overflow See other posts from Stack Overflow or by PoltoS
Published on 2011-01-05T01:38:00Z Indexed on 2011/01/05 1:54 UTC
Read the original article Hit count: 576

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 to 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?

© Stack Overflow or respective owner

Related posts about JavaScript

Related posts about jQuery