In response to my answer yesterday about rotating an Image, Jamund told me to use .data()
instead of .attr()
First I thought that he is right, but then I thought about a bigger context... Is it always better to use .data()
instead of .attr()
? I looked in some other posts like what-is-better-data-or-attr or jquery-data-vs-attrdata
The answers were not satisfactory for me...
So I moved on and edited the example by adding CSS. I thought it might be useful to make a different Style on each image if it rotates. My style was the following:
.rp[data-rotate="0"] {
border:10px solid #FF0000;
}
.rp[data-rotate="90"] {
border:10px solid #00FF00;
}
.rp[data-rotate="180"] {
border:10px solid #0000FF;
}
.rp[data-rotate="270"] {
border:10px solid #00FF00;
}
Because design and coding are often separated, it could be a nice feature to handle this in CSS instead of adding this functionality into JavaScript. Also in my case the data-rotate
is like a special state which the image currently has. So in my opinion it make sense to represent it within the DOM.
I also thought this could be a case where it is much better to save with .attr()
then with .data()
. Never mentioned before in one of the posts I read.
But then i thought about performance. Which function is faster? I built my own test following:
<!DOCTYPE HTML>
<html>
<head>
<title>test</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript">
function runfirst(dobj,dname){
console.log("runfirst "+dname);
console.time(dname+"-attr");
for(i=0;i<10000;i++){
dobj.attr("data-test","a"+i);
}
console.timeEnd(dname+"-attr");
console.time(dname+"-data");
for(i=0;i<10000;i++){
dobj.data("data-test","a"+i);
}
console.timeEnd(dname+"-data");
}
function runlast(dobj,dname){
console.log("runlast "+dname);
console.time(dname+"-data");
for(i=0;i<10000;i++){
dobj.data("data-test","a"+i);
}
console.timeEnd(dname+"-data");
console.time(dname+"-attr");
for(i=0;i<10000;i++){
dobj.attr("data-test","a"+i);
}
console.timeEnd(dname+"-attr");
}
$().ready(function() {
runfirst($("#rp4"),"#rp4");
runfirst($("#rp3"),"#rp3");
runlast($("#rp2"),"#rp2");
runlast($("#rp1"),"#rp1");
});
</script>
</head>
<body>
<div id="rp1">Testdiv 1</div>
<div id="rp2" data-test="1">Testdiv 2</div>
<div id="rp3">Testdiv 3</div>
<div id="rp4" data-test="1">Testdiv 4</div>
</body>
</html>
It should also show if there is a difference with a predefined data-test
or not.
One result was this:
runfirst #rp4
#rp4-attr: 515ms
#rp4-data: 268ms
runfirst #rp3
#rp3-attr: 505ms
#rp3-data: 264ms
runlast #rp2
#rp2-data: 260ms
#rp2-attr: 521ms
runlast #rp1
#rp1-data: 284ms
#rp1-attr: 525ms
So the .attr()
function did always need more time than the .data()
function. This is an argument for .data()
I thought. Because performance is always an argument!
Then I wanted to post my results here with some questions, and in the act of writing I compared with the questions Stack Overflow showed me (similar titles)
And true enough, there was one interesting post about performance
I read it and run their example. And now I am confused! This test showed that .data()
is slower then .attr()
!?!! Why is that so?
First I thought it is because of a different jQuery library so I edited it and saved the new one. But the result wasn't changing...
So now my questions to you:
Now depending on the performance:
.attr()
instead of data, if it shows that .attr()
is better? Although data is meant to be used for .data()
?UPDATE 1:
I did see that without overhead .data()
is much faster. Misinterpreted the data :) But I'm more interested in my second question. :)
Would you prefer to use data- HTML5 attributes instead of data, if it represents a state? Although it wouldn't be needed at the time of coding? Why - Why not?
Are there some other reasons you can think of, to use .attr()
and not .data()
? e.g. interoperability? because .data()
is jquery style and HTML Attributes can be read by all...
UPDATE 2:
As we see from T.J Crowder's speed test in his answer attr
is much faster then data
! which is again confusing me :) But please! Performance is an argument, but not the highest! So give answers to my other questions please too!
UPDATE 3:
My test seems to be false because of the fire-bug I used while testing! The same file in chrome listed attr
faster and a second test on jsperf also says attr
is faster
data-* attributes allow us to store extra information on standard, semantic HTML elements without other hacks such as non-standard attributes, or extra properties on DOM.
CSS data types define typical values (including keywords and units) accepted by CSS properties and functions. They are a special kind of component value type. The most commonly-used types are defined in the CSS Values and Units specification.
In short, a data attribute is a single-value descriptor for a data point or data object. It exists most often as a column in a data table, but can also refer to special formatting or functionality for objects in programming languages such as Python.
This performance part of the question screams of premature optimization; see below. (Lest you get the wrong idea: I too am frequently guilty of wondering about the same sort of premature optimization question.)
But getting performance out of the way (other points addressed below the graph): As far as I can see, attr
is faster than data
in jQuery 1.7.1: http://jsperf.com/jquery-setting-attr-vs-data This surprises me. Not that it's remotely likely to matter.
Gratuitous bar graph (longer lines = faster performance):
Are there some other reasons you can think of, to use .attr() and not .data()?
At least a couple come to mind:
The advantage of data
is that it doesn't have to write to the element every time; you only write to the actual element the first time, and from then on jQuery is just updating a value in a JavaScript object it maintains in a separate object cache (connected to the element via a key). (I'm not sure why it's slower than attr
; perhaps because of the indirection.)
One thing I dislike about data
is that it's not symmetrical: The first time you access data
on an element, the data object is seeded with data-*
attributes from the element; but from there on out, there is no connection between the two.
Example (live copy | live source):
var target = $("#target");
display("data('foo'): " + target.data("foo"));
display("data-foo: " + target.attr("data-foo"));
display("Setting data('foo')");
target.data("foo", "updated data('foo')");
display("data('foo'): " + target.data("foo"));
display("data-foo: " + target.attr("data-foo"));
display("Setting data-foo");
target.attr("data-foo", "updated data-foo");
display("data('foo'): " + target.data("foo"));
display("data-foo: " + target.attr("data-foo"));
Assuming the #target
element starts out with data-foo="bar"
, the output is:
data('foo'): bar data-foo: bar Setting data('foo') data('foo'): updated data('foo') data-foo: bar Setting data-foo data('foo'): updated data('foo') data-foo: updated data-foo
That can be confusing and surprising. The way you have to think about it is that the data-*
attributes are default values only. I just don't like how they're so dependent on whether you've called data
before or not; unless you never write to the data-*
attribute directly, you can't be sure what value data
will get (the original from the markup, or a value you updated later before you called data
). It seems a bit chaotic to me, but if you set yourself rules (never write to data-*
attributes directly and only ever use data
, for instance), you can avoid the chaos.
When you use attr
, you can only store strings. When you use data
, you can store any JavaScript value or object reference.
Because performance is always an argument!
Not in 2012. :-) Or at least, it's a lot lower down the list relative to other arguments than it used to be absent a specific, demonstrable performance problem.
Let's look at your runfirst #rp4
results: 10k iterations of attr
took 515ms; 10k iterations of data
took 268ms. That's 51.5 usec (microseconds, millionths of a second) each vs. 26.8 usec each. So you're wondering whether to use data
if it saves you 24.7 usec per operation. Humans perceive things on the order of tenths of seconds. So for it to matter, you have to do this op roughly 4,000 times in a tight loop for a human to notice the difference. That's just not even close to worth worrying about, even in a mousemove
handler.
If you're into that kind of territory (4,000/second in a tight loop), you'll probably want to avoid storing the information on the element at all.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With