$ .each()vs for()循环-和性能


75

这些主要只是我一直想知道的事情,也许有人可以给我更多关于它们的见解,我将分享到目前为止我已经注意到的内容!

我一直想知道的第一件事...使用的好处或理由有什么不同:

$('element').each(function (i, el) { });

- 与 -

$.each($('element'), function (i, el) { });

查看jQuery文档,我看不到任何一个韵律或原因(也许您知道一个实例或其他可以做的事情)。

但更重要的是我在这里关心速度

// As opposed to $.each() looping through a jQuery object
// -- 8x faster 
for (var i = 0, $('.whatever').length; i < len; i++) {
    $('.whatever')[i] // do stuff
}

如果您在此处查看此jsFiddle DEMO,您将看到速度差异基本上与它们中的任何一个相等,但更重要的是,我觉得我应该始终使用for()循环...

我只是进行单元测试(遍历5个不同的场景功能中的每一个,50,000次),仅遍历一堆列表项,并设置a data-newAttr,没什么特别的。


问题::我猜我最大的问题是,为什么在遍历对象时不总是使用for循环?甚至还有使用$ .each()的意义吗?即使遍历jQuery对象,您是否总是使用for()循环?

jsFiddle演示在这里

Function type:                  Execution Time:
_testArea.each() + $(this)               1947   <-- using $(this) slows it down tremendously
$.each()         + $(this)               1940
_testArea.each() + el(plain JS)           458   <-- using the Element speeds things up
$.each()         + el(plain JS)           452
for() loop       + plainJS[0] iteration   236   <-- over 8x faster

就是我的2美分。:)


31
正如乔·阿姆斯特朗(Joe Armstrong)在回答Erlang邮件列表上的类似问题时所写的那样,“只要编写出最漂亮的程序就可以。” 让性能问题来解决。您真的会在迭代50,000次的页面上工作吗?如果是,那么一定要优化。
Pointy 2012年

3
for遍历jQuery DOM元素的循环是什么样的?
约旦

2
在jsperf.com上自行测试
j08691'8

1
总是,Javascript函数会比Jquery Function快,因为javascript是本机,但是我认为使用each代替for的目的是,它使使用框架的代码更快,并且具有优点
Jorge 2012年

5
.each()方法遍历jQuery对象。该$.each()静态方法可以遍历各种类型的对象,就像普通的物体,阵列,和阵列状物体。就是这样。
席姆·维达斯

Answers:


47

.each()允许您执行for循环操作无法完成的一件事是链接

$('.rows').each(function(i, el) {
    // do something with ALL the rows
}).filter('.even').each(function(i, el) {
    // do something with the even rows
});

我与您的JSFiddle一起玩耍,以了解在您必须遍历原始匹配元素集的子集的情况下,链接将如何影响性能。

结果并不是出乎意料的,尽管我认为end()由于少量元素和许多循环的结合,此处的开销被夸大了。除此之外,普通的JS循环仍然略快一些,但是这是否会影响.each()(和链接)附加的可读性尚有争议。


哇!谢谢,甚至都没有考虑过这样的链接,这本身就是一个很大的好处!在普通的JS中要做的代码太多了,一旦发生一堆if / else事件来完成同一件事,那么ms的好处就几乎不存在了。
Mark Pieszak-Trilon.io,2012年

1
表现不佳!我会在外部的each()内部进行过滤,只是因为each()。filter()将处理同一数组两次,其不那么方便,但性能更高。如果你期望元素的大数目,那么我会使用在所有的每一个()迭代放弃,只是看看jsperf.com/function-call-overhead-test关于函数调用的开销
comeGetSome

22

您要做的一件事.each()是自动局部作用域(因为您正在为每个对象调用一个匿名函数),这反过来意味着,如果您要创建更多的匿名函数/闭包/事件处理程序/无论每次迭代如何,您都不必担心您的处理程序共享变量。也就是说,就本地范围而言,JavaScript不像其他语言那样工作,但是因为您可以在任何地方声明变量,所以有时它会欺骗您。

换句话说,这是错误的:

var idx,el;
for (idx = 0; idx <someObjectArray.length; idx++){
   el = someObjectArray[idx]
   el.someEventHandler(function(){  
       alert( "this is element " + idx);
   }); 
}

每当这些对象中的任何一个在此循环后调用它们的“ someEvent”时(请注意,这是组成的),警报总是会说最后分配给的对象idx,应该是(被调用时)someObjectArray.length

为了确保保存正确的索引,您必须声明一个局部作用域,创建一个变量并分配给该变量以供使用。

var idx,el;
for (idx = 0; idx <someObjectArray.length; idx++){
   el = someObjectArray[idx];
   (function(){
       var localidx = idx;
       el.someEventHandler(function(){  
           alert( "this is element " + localidx);
       }); 
   })();
}

如您所见,这很可怕,但是应该可以。每个事件处理程序都有自己的副本localidx

现在比较一下 .each()

$(someObjectArray).each(function (idx, el) { 
   el.someEventHandler(function(){  
       alert( "this is element " + idx);
   }); 
});

简单得多,不是吗?


1
非常真实!我实际上忘记了一秒钟,它已经为您做到了...我想,最大的收获就是如果您想要简单的操作| 获得/设置类型的东西,简单的for()w普通JS确实是可行的方法。对于更复杂的过滤和事件处理程序,几乎需要使用each()。有趣的...
Mark Pieszak-Trilon.io,2012年

9

jQuery.each与for循环

优点jQuery.each:

  • 非常适合jQuery代码(链接和样式)。
  • 不用担心范围(对迭代器和对象的引用将是持久的)。
  • 可以通用使用(用于所有类型的对象并遍历对象键)。

循环优势:

  • 高性能(用于游戏/动画/大型数据集)。
  • 完全控制迭代器(跳过项,列表中的拼接项等)。
  • for循环将始终有效,因为它不依赖jQuery。
  • 与大多数其他类似语言相同的语法。

范例程式码

这是我更喜欢遍历列表的示例代码。

var list = ['a', 'b', 'c', 'd', 'e', 'f'];

jQuery.each:

$.each(list, function(i, v)
{
    // code...
});

For循环,无闭包:

for(var i=0,v,n=list.length;i<n;i+=1)
{
    v = list[i];
    // code...
}

带闭环的for循环:

for(var i=0,n=list.length;i<n;i+=1)
{
    (function(i, v)
    {
        // code...
    })(i, list[i]);
}

注意:我建议您只使用标准的for循环,并且仅在必要时使用闭包。但是,无论如何,当您的代码看起来更像jQuery而不是Javascript时,仅使用它可能会更容易$.each。如果出现性能问题,您以后可以随时进行调查。



4

当我转到您的链接时,这里有两个数字:

$.each() + el(plain JS) 401
for() loop + plainJS[0] iteration   377

如果差异很小,那么请选择可读性最强的产品,但是,如果您对时间的要求很高,则可能只需要选择最快的产品即可。

我建议您编写程序以使用三种不同的方法,即上述两种,然后使用在较新版本的javascript中找到的foreach,对于不支持它的浏览器,可以将其添加为原型。

https://developer.mozilla.org/zh-CN/docs/JavaScript/Reference/Global_Objects/Array/forEach

您知道自己的要求以及程序将执行的操作,因此只需编写您自己的测试,并确保它满足您将支持的浏览器中的要求。

对于您的第一个问题,我会同意,$('element').each因为它很容易阅读,但这只是我的观点。


2
尽管对于这么小的利润,它可能并不会造成什么区别[。带有垃圾邮件的押韵] ..我将只使用“更清晰一致的版本”(无论确定为哪个版本),除非存在特定的实际性能情况表明它太慢了。

1
@pst-如果您调用10000次,那么小的保证金会有所不同,而这个很小的差别会使您超出允许的范围,这正是我要问的,真正了解的唯一方法是使用三个版本并获得一些数字。
詹姆斯·布莱克

谢谢詹姆斯!是的,在我看来,这绝对是一个问题,我们需要支持旧版浏览器,但是现在我看到了可读性和可链接性-明智的做法-使用起来很有意义each(),然后坚持使用纯文本JS!区别实际上是不存在的,似乎除非我需要它来保留JS对象,否则不需要使用$(this)
Mark Pieszak-Trilon.io,2012年

2

实际上,$ .each()和$()。each()之间有很大的区别。

根据您要传递的内容,它们执行的操作略有不同。

http://api.jquery.com/each/http://api.jquery.com/jquery.each/

jquery.each是一个通用的迭代器,其中$()。each()特定于jquery集合。

另请参阅:http : //jsperf.com/each-vs-each-vs-for-in/9


您可以使用相同的方式轻松地使用这两种方式:$(['someItem', 'anotherItem']).each(function (i, el) { }); jsfiddle.net/zzVQD。同样,这并不意味着这个问题值得批评,我为此投入了大量研究/代码/努力。
Mark Pieszak-Trilon.io

1
尽管这不是该问题的答案,但它增加了一些知识。
互换
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.