Skip to content Skip to sidebar Skip to footer

Save Object States In .data Or Attr - Performance Vs CSS?

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 con

Solution 1:

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

Gratuitous bar graph from jsperf

Are there some other reasons you can think of, to use .attr() and not .data()?

At least a couple come to mind:

  1. 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.)

  2. 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.

  3. 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.


Solution 2:

Given that .data() is indeed slower than .attr() on most browsers, but the speed difference is not important in this question, one advantage of data() over attr() is that data will automatically coerce data- attributes to numbers or to boolean values if they match.

That means that

<div id="boolean" data-t="true" data-f="false">

will result in boolean runtime value of true & false when you run this:

console.log($('#boolean').data('t'));  // reports true (not a string)
console.log($('#boolean').data('f'));  // reports false (not a string)

and

<div id="number" data-n="123.456">

will result in a number runtime value of 123.456 when you run this:

console.log($('#number').data('n'));  // Reports 123.456 (not a string)

attr on the other hand only works with strings, but will convert value to strings for saving. It will not coerce values when you fetch them.

The choice between attr and data depends on the feature you need for a specific example:

  • Where I inject data- settings from the server into pages, I tend to use data() to access them, if only because it is shorter code.
  • If I need the data to be visible in the DOM, I will use attr() to save the values`.

Solution 3:

You may use jQuery.data. It's almost always the fastest. jQuery tries to optimize its function on every browsers, and maximize compability. So with new versions of jQuery, you may gain performance for this function. This 2nd test gave me jQuery.data as the winner.


Post a Comment for "Save Object States In .data Or Attr - Performance Vs CSS?"