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

IT技术 javascript jquery
2021-02-01 22:25:07

这些主要只是我一直想知道的一些事情,也许有人可以让我对它们有更多的了解,我也会分享我到目前为止所注意到的!

我一直想知道的第一件事......是否有任何不同的好处或使用理由:

$('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 次),简单地遍历一堆列表项,并设置一个data-newAttr,没什么特别的。


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

jsFiddle DEMO 在这里

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 美分。:)

6个回答

.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 的好处几乎不存在。
2021-03-23 22:25:07
表现不佳!我会在外部 each() 内部进行过滤,因为 each().filter() 会处理相同的数组两次,它不太方便但性能更高。如果您期望有大量元素,那么我将完全避免使用 each() 迭代,只需查看有关函数调用开销的jsperf.com/function-call-overhead-test
2021-04-13 22:25:07

你得到的一件事.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);
   }); 
});

简单多了,不是吗?

非常真实!我实际上忘记了一秒钟它已经为你做了这个......我想从中得到的最大的事情是,如果你想要简单的操作 | get/set 类型的东西很容易 for() w 纯 JS 真的是要走的路。对于更复杂的过滤和事件处理程序,您几乎需要 each()。有趣的...
2021-04-06 22:25:07

jQuery.each 与 for 循环

jQuery.each 的优点:

  • 非常适合 jQuery 代码(链接和样式)。
  • 不用担心范围(对迭代器和对象的引用将是持久的)。
  • 可以普遍使用(用于各种对象和迭代对象键)。

for循环的优点:

  • 高性能(适用于游戏/动画/大型数据集)。
  • 完全控制迭代器(跳过项目、从列表中拼接项目等)。
  • 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. 如果出现性能问题,您可以事后随时查看。

之前我运行了一些简单的性能测试http://jsperf.com/forloops3似乎坚持简单,旧for loop(可能的地方)是要走的路:)

当我访问您的链接时,我得到了两个数字:

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

如果差异很小,那么选择可读性最高的那个,但是,如果您有非常高的时间要求,那么您可能只需要选择最终最快的那个。

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

https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach

您知道您的要求是什么,以及您的程序将做什么,因此只需编写您自己的测试并确保它满足您将支持的浏览器的要求。

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

@pst - 如果你调用它 10000 次,那么小的边距会产生影响,而这个小差异会使你超出允许的窗口,这就是我要问的,真正知道的唯一方法是在各种浏览器上进行测试三个版本并得到一些数字。
2021-03-16 22:25:07
尽管对于如此小的利润,它可能不会使 [与垃圾邮件押韵] 有点不同......我只会使用“更清晰一致的版本”(无论哪个版本),除非有特定的现实世界的表现案例表明它太慢了。
2021-03-17 22:25:07
谢谢詹姆斯!是的,就我而言,这绝对是一个问题,我们需要支持旧版浏览器,但现在我看到可读性和可链接性 - 明智- 使用 是有意义的each(),然后坚持使用纯 JS!差异确实不存在,似乎除非我需要它保持 JS 对象,否则我不需要使用$(this).
2021-04-08 22:25:07