在.data或attr中保存对象状态 - Performance vs CSS?

Ney*_*sor 14 javascript css performance jquery html5

为了回应我昨天关于旋转图像的回答,Jamund告诉我使用.data()而不是.attr()

首先我认为他是对的,但后来我想到了一个更大的背景 ......是否总是更好地使用.data()而不是.attr()?我查了一些其他帖子,比如what-is-better-data-or-attrjquery-data-vs-attrdata

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

所以我继续并通过添加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;
}
Run Code Online (Sandbox Code Playgroud)

由于设计和编码通常是分开的,因此在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>
Run Code Online (Sandbox Code Playgroud)

它还应该显示是否与预定义有区别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
Run Code Online (Sandbox Code Playgroud)

所以.attr()函数总是需要比.data()函数更多的时间.这是.data()我想的一个论据.因为表现总是一个论点!

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

事实上,有一篇关于表现的有趣帖子

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

首先我认为这是因为一个不同的jQuery库所以我编辑并保存了新的.但结果并没有改变......

所以现在我向你提问:

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

现在取决于性能:

  • .attr()如果表现出.attr()更好的表现,性能会成为你使用而不是数据的论据吗?虽然数据是用于.data()

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

如果它代表一个状态,你更愿意使用data-HTML5属性而不是数据吗?虽然在编码时不需要它?为什么 - 为什么不呢?

您是否有其他原因可以考虑使用.attr()而不是.data()?例如互操作性?因为.data()是jquery样式和HTML属性可以被所有人阅读...

更新2:

正如我们从TJ Crowder速度测试中看到的那样,答案 attr要快得多data!这再次让我困惑:)但请!表演是一个争论,但不是最高的!所以也请回答我的其他问题!

更新3:

我的测试,似乎是因为的是假火的bug在测试我使用!chrome中的相同文件列出的attr速度更快,而对jsperf的第二次测试也说得attr更快

T.J*_*der 15

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

但越来越表现出来的方式(解决图形下方的其他分):据我所看到的,attr是速度比data在jQuery的1.7.1:http://jsperf.com/jquery-setting-attr-vs-data这让我感到惊讶.并不是说它很可能很重要.

免费条形图(更长的线条=更快的性能):

来自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"));
    
    Run Code Online (Sandbox Code Playgroud)

    假设#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),就可以避免混乱.

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


因为表现总是一个论点!

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

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

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