在.data或attr中保存对象状态 - 性能与CSS?

时间:2012-03-20 08:39:24

标签: javascript jquery css performance html5

针对我的answer yesterday关于旋转图片的回复,Jamund告诉我使用.data()代替.attr()

首先我认为他是对的,然后我考虑了更大的背景 ...使用.data()代替.attr()总是更好吗?我查看了其他一些帖子,例如what-is-better-data-or-attrjquery-data-vs-attrdata

答案对我来说不满意......

所以我继续前进并edited the example通过添加CSS。我认为如果每个图像旋转,在每个图像上创建一个不同的样式可能会有用。我的风格如下:

.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;
}

由于设计和编码经常是分开的,因此在CSS中处理此问题可能是一个很好的功能,而不是将此功能添加到JavaScript中。同样在我的情况下,data-rotate就像特殊状态图像当前具有。因此,在我看来,在DOM中表示它是有意义的。

我还认为这可能是使用.attr().data()保存更好的情况。 以前从未在我读过的其中一篇文章中提到过。

但后来我考虑了性能。哪个功能更快?我建立了自己的测试:

<!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>

它还应该显示预定义的data-test是否存在差异。

结果是:

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

因此.attr()函数总是需要比.data()函数更多的时间。这是我认为的.data()的论据。因为表现永远是一个争论!

然后我想在这里发布我的结果并提出一些问题,并且在写作的过程中,我与Stack Overflow向我展示的问题进行了比较(类似标题)

而且确实有一个interesting post about performance

我读了它并运行他们的例子。现在我很困惑! 此测试显示.data().attr()慢!?!!为什么会这样?

首先我认为这是因为一个不同的jQuery库所以我编辑了它并saved the new one。但结果并没有改变......

所以现在我向你提问:

  • 为什么这两个例子的表现存在一些差异?
  • 如果它代表一个州,您是否愿意使用数据-HTML5属性而不是数据?虽然在编码时不需要它?为什么 - 为什么不呢?

现在取决于表现:

  • 如果.attr()显示.attr()更好,那么使用.data()而不是数据,性能会成为您的理由吗?虽然数据旨在用于.data()

更新1:
我确实看到没有开销.attr()要快得多。误解了数据:)但我对第二个问题更感兴趣。 :)

  

您是否愿意使用数据-HTML5属性而不是数据(如果是)   代表一个国家?虽然在当时不需要它   编码?为什么 - 为什么不呢?

您是否还有其他一些理由可以考虑使用.data()而不是.data()?例如互操作性?因为attr是jquery样式,所有人都可以读取HTML属性...

更新2:

我们从T.J Crowder speed test his answer data attr看到的速度比attr快得多!这再次让我困惑:)但请!表演是一个争论,但不是最高的!所以也请回答我的其他问题!

更新3:

我的测试似乎是假的,因为我在测试时使用了fire-bug! Chrome中的同一文件{{1}}更快,jsperf上的第二次测试也表示{{1}}更快

3 个答案:

答案 0 :(得分:15)

这个性能部分的问题尖叫过早优化;见下文。 (以免你得到错误的想法:我经常因为想到同样的过早优化问题而感到内疚。)

但要让性能不受影响(图表下方的其他要点):据我所知,attr比jQuery 1.7.1中的data更快:http://jsperf.com/jquery-setting-attr-vs-data这让我感到惊讶。并不是说它很可能很重要。

免费条形图(较长的行=较快的性能):

Gratuitous bar graph from jsperf

  

您是否还有其他一些理由可以使用.attr()而不是.data()?

至少有一对想到:

  1. data的优点是每次都不必写入元素;你只是第一次写入实际的元素,从那时起jQuery只是更新它在一个单独的对象缓存(通过一个键连接到元素)中维护的JavaScript对象中的值。 (我不确定为什么它比attr慢;也许是因为间接。)

  2. 我不喜欢data的一点是它不对称:第一次访问元素上的data时,数据对象将使用data-*属性来播种元件;但从那以后,两者之间没有联系。

    示例(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"));
    

    假设#target元素以data-foo="bar"开头,输出为:

    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

    这可能令人困惑和惊讶。您必须考虑的方式是data-*属性仅为默认值。我只是不喜欢他们如何依赖你之前是否打过data;除非您从不直接写入data-*属性,否则您无法确定将获得的值data(标记中的原始值,或之前更新的值)你打电话给data)。对我来说似乎有点混乱,但如果你自己设定规则(永远不要直接写data-*属性,只使用data),你就可以避免混乱。

    < / LI>
  3. 使用attr时,只能存储字符串。使用data时,您可以存储任何JavaScript值或对象引用。


  4.   

    因为表演总是一个论点!

    不是在2012年。:-)或者至少,相对于其他论点,它在列表中的位置比以前缺少特定的,可证明的性能问题要低很多。

    让我们看一下你的runfirst #rp4结果:attr的10k次迭代需要515毫秒; data的10k次迭代耗时268ms。这是51.5 usec(微秒百万分之一秒),每个26.8 usec。所以你想知道是否使用data,如果每次操作可以节省24.7 usec。人类在十分之几秒的时间内感知事物。因此,重要的是,你必须在一个紧密的循环中做大约4000次,以便人类注意到差异。即使在mousemove处理程序中,这甚至都不值得担心。

    如果你进入那种领域(紧密循环中为4,000 /秒),你可能想要避免将信息存储在元素上。

答案 1 :(得分:1)

鉴于.data()确实比.attr() on most browsers慢,但速度差异在此问题中并不重要,data()优于attr()的一个优势如果数据匹配,数据会自动将data-属性强制转换为numbersboolean值。

这意味着

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

将导致布尔运行时值为true&amp;运行时false

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

<div id="number" data-n="123.456">
运行此命令时,

将导致数字运行时值为123.456

console.log($('#number').data('n'));  // Reports 123.456 (not a string)
另一方面,

attr仅适用于字符串,但会将值转换为字符串以进行保存。当你获取它时,它不会强制赋值。

attrdata之间的选择取决于特定示例所需的功能:

  • 如果我将data-设置从服务器注入页面,我倾向于使用data()来访问它们,只是因为它是更短的代码。
  • 如果我需要在DOM中显示数据,我将使用attr()来保存值。

答案 2 :(得分:0)

您可以使用jQuery.data。它几乎总是最快的。 jQuery尝试在每个浏览器上优化其功能,并最大化兼容性。因此,对于新版本的jQuery,您可以获得此功能的性能。 This 2nd test给了我jQuery.data作为获胜者。