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.
精彩评论