jQuery: add() 性能问题;是否有更好的方法?

5
我想做的是:将页面上所有相同类型的元素分组到一个对象中,以便稍后进行迭代或对每个元素应用全局更改。
我的代码可以成功完成所需任务,但当元素数量增加到200-300+时,性能急剧下降,用户已经注意到。我已经确定了有问题的代码行,并想知道是否有另一种解决方法。
根据我放置的计时器,add()函数似乎是有问题的操作。起初,执行该操作所需的时间为0.001秒,但随着元素数量达到300,它需要每增加一个元素就需要约0.1秒,并且继续变慢。
我已经研究了jQuery的性能增强能力(以及其他),并且实施了其中的一些(即3个),但它们没有给我带来任何有意义的性能提升。令人惊讶的是,这段代码在Firefox中的执行时间仅为1秒(对add()函数调用300+次),而Chrome和IE则需要10-20倍甚至更长时间……

这是我的代码:

rowsToChange = $([]);
// Grab all the ids greater than whichever one I'm currently looking at:
var arr = $.makeArray($("[id^=stackLocatorLinkFillUp]:gt("+(uniqueID-1)+")"));
for (var i=0; i<arr.length; i++) {
    $this = arr[i];
    // <<< VARIOUS CONDITIONALS that make this as selective as possible REMOVED >>>
    startTimer = new Date().getTime();
    // **************************
    // PROBLEMATIC LINE FOLLOWS when 200+ records:
    rowsToChange = rowsToChange.add($this);
    // Grows from .001 to .1xx after 300 iterations
    console.log("innertiming:"+(new Date().getTime() - startTimer)/1000);
    // **************************
}

最终结果看起来像这样(通过Chrome检查器):
[<div style=​"display:​none" id=​"stackLocatorLinkFillUp1">​itemType=BOUND&ccLocale=PERIODICAL​</div>​, 
<div style=​"display:​none" id=​"stackLocatorLinkFillUp2">​itemType=BOUND&amp;ccLocale=PERIODICAL​</div>​,
...
]

最终,我按照以下方式处理所有这些内容(我喜欢这种简单易行的方式!):
var superlink = "...new <a> goodness to display for all elements...";
rowsToChange.html(superlink).css("display","block");

这看起来可能是一个有效的解决方案(不同的添加方法?),但我更喜欢继续将对象列表聚集在一起,以便最后一行可以发挥其魔力。
(am not i am指出以下内容不正确--关于连接; 感谢'am not i am')
似乎add()操作必须连接字符串,因为这似乎是其他人面临的主要问题之一。但将我的add()语句转换为+=似乎不起作用。
感谢您查看;
Chrome:18.0.1025.142 m Firefox:11.0 IE:8.0.7600.16385

什么是“超链接”?你没有展示出你对“rowsToChange”具体的操作。 - Pointy
.add() 方法绝对不会将字符串连接起来。DOM 不是字符串。您可能想看一下 .pushStack() - user1106925
谢谢 Pointy;在我的真实代码中,我抽象了该方法并得到了一个新名称;superlink被赋予了一个占位符。对于造成的困惑,我很抱歉。 - veeTrain
感谢“我不是我”; 我目前正在实施DCoder建议的解决方案。相比于add(),它看起来将会成功并且速度非常快。 - veeTrain
2个回答

5

第一点观察: add 会保存先前的元素集。尝试使用 rowsToChange = jQuery.merge(rowsToChange, [$this]); 替代。

第二点观察:似乎 rowsToChange 最终会成为你调用 $.makeArray 的完全相同的元素集。为什么不保存原始的集合呢?


回复: 第二条观察; 很好的点子!我没有包含所有的代码,以免分散注意力;有许多条件必须发生才能被添加到rowsToChange :-) 我正在尝试您的合并想法! - veeTrain
DCoder -- 非常棒的建议,你的第一个观察似乎是我需要的解决方案;它的表现几乎太快了,难以置信,所以我会三重检查,但很可能会回来并接受你的答案。非常感谢!(附注:合并要求我在 $this 周围放置 []) - veeTrain
DCoder:我已经接受了你的答案并实现了它,真是太棒了!它完全符合我的要求,并且在所有三个浏览器上运行速度非常快。然而,我之前提到需要在[$this]周围加上括号的问题已经改变了。显然,在使用$.each()循环时,括号是不必要的(正如你所怀疑的那样),而在使用for循环时则是_必要的_。我会在新答案中提到这两种情况,但仍然接受你的答案。非常感谢! - veeTrain

0

如果您正在使用for循环,DCoder展示了如何适当地合并信息。然而,如果您在这里使用.each()循环,请使用以下内容。

主要区别是取决于'this'的结构,括号是否必要/不必要。此外,似乎普遍认为.each()比本机javascript for循环至少稍微慢一些。(来源:2009年的证据) (从上面的问题复制的定时测试)

var $this, rowsToChange = $([]);
// slower than a for loop
$("[id^=stackLocatorLinkFillUp]:gt("+(uniqueID-1)+")").each( function() {
    // If statements <removed> that decide whether or not to include in the new container
    $this = $(this); // probably unnecessary under most situations
    rowsToChange = jQuery.merge(rowsToChange, $this);
});

对被移除的 if 语句决定的每个新子组进行操作!

rowsToChange.html("...");

感谢所有查看问题、抽出时间回答、投票支持等的人!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接