【问题标题】:Alternatives to javascript function-based iteration (e.g. jQuery.each())javascript 基于函数的迭代的替代方案(例如 jQuery.each())
【发布时间】:2010-11-30 21:28:03
【问题描述】:

我一直在观看 Google Tech Talks 的 Speed Up Your Javascript,在谈论循环时,演讲者提到要远离基于函数的迭代,例如 jQuery.each()(其中包括,大约 24:05 在视频)。他简要解释了为什么要避免它们,这是有道理的,但我承认我不太明白替代方案是什么。比如说,如果我想遍历一列表格单元格并使用该值来操作相邻单元格的值(只是一个简单的示例)。任何人都可以解释并举例说明基于函数的迭代的替代方法吗?

【问题讨论】:

    标签: javascript loops iteration


    【解决方案1】:

    如果需要循环,只需一个简单的 for 循环应该会更快。

    var l = collection.length;
    for (var i = 0; i<l; i++) {
      //do stuff
    } 
    

    但是,仅仅因为它更快并不意味着它总是那么重要。

    这在客户端而不是服务器上运行,因此您无需担心随着用户数量的增加而扩展,如果使用 .each() 可以快速完成,则不要使用它。但是,如果这很慢,那么 for 循环可以加快速度。

    【讨论】:

    • javascript 中快速迭代的方式是 do { // 要执行的代码 } while (--currentIndex) 当然你只能在顺序无关紧要的时候使用它(或者相反的顺序是可取的)
    • 我一般用for(var i = foo.length; i--; ) {};带有预减量的 do..while 循环可能会更快,但实际上差异并不重要
    • @klaaspieter,您可以简单地使用 ++currentIndex 反转顺序,并在块之前执行 currentIndex *= -1;
    • @Dykam,这很难阅读,它有效,但它被过度混淆了
    【解决方案2】:

    老循环

    【讨论】:

      【解决方案3】:

      在我看来,基于函数的迭代会稍微慢一些,因为 1) 函数本身的开销,2) 创建和执行 N 次回调函数的开销,以及 3)范围链中的额外深度。但是,我想我会为踢球做一个快速的基准测试。结果证明,至少在我的简单测试用例中,基于函数的迭代更快。这是代码和结果

      测试基准代码

      // Function based iteration method
      var forEach = function(_a, callback) {
        for ( var _i=0; _i<_a.length; _i++ ) {
          callback(_a[_i], _i);
        }
      }
      
      // Generate a big ass array with numbers 0..N
      var a = [], LENGTH = 1024 * 10;
      for ( var i=0; i<LENGTH; i++ ) { a.push(i); }
      
      console.log("Array length: %d", LENGTH);
      
      // Test 1: function-based iteration
      console.info("function-base iteration");
      var end1 = 0, start1 = new Date().getTime();
      
      var sum1 = 0;
      forEach(a, function(value, index) { sum1 += value; });
      
      end1 = new Date().getTime();
      console.log("Time: %sms; Sum: %d", end1 - start1, sum1);
      
      // Test 2: normal for-loop iteration
      console.info("Normal for-loop");
      var end2 = 0, start2 = new Date().getTime();
      
      var sum2 = 0;
      for (var j=0; j<a.length; j++) { sum2 += a[j]; }
      
      end2 = new Date().getTime();
      console.log("Time: %sms; Sum: %d", end2 - start2, sum2);
      

      每个测试只是对数组求和,这很简单,但可以在某种现实生活场景中真实地看到。

      FF 3.5 的结果

      Array length: 10240
      function-base iteration
      Time: 9ms; Sum: 52423680
      Normal for-loop
      Time: 22ms; Sum: 52423680
      

      事实证明,在这个测试用例中,基本的 for 迭代更快。我还没有看过视频,但我会看一下,看看他是否在某个地方有所不同,这会使基于函数的迭代变慢。

      编辑:这绝不是最终结果,只是一个引擎和一个测试用例的结果。我完全预期结果会相反(基于函数的迭代速度较慢),但有趣的是看看某些浏览器是如何进行优化的(可能是也可能不是专门针对这种 JavaScript 风格的),因此反之亦然。

      【讨论】:

      • 因为你使用了“j
      • 我完全了解这种优化;但是,它不应该对该测试产生任何影响,因为您会注意到两个for 循环在结构上是相同的并且缺乏优化。但是,由于第一次测试显示出意想不到的结果,我将使用该优化再次运行它,看看它是否会改变任何东西,但我现在不相信它会改变。两次迭代都应该减少相似的数量。
      • @chad 正如我所怀疑的,这种优化并没有显着改变测试结果。事实上,我认为这是对这种数据结构的错误优化。对于实时数据结构(如 dom 容器),这种优化很有用。
      • 我刚刚在 IE 7 中运行了您的脚本几次,结果与您的不同。基于函数的循环采用一致的 31 或 32 毫秒,标准循环采用 15 或 16 毫秒。
      • @Justin,发生了一些奇怪的事情。因为没有任何数学方法可以让我想到一个在内部使用相同 for 循环的函数比单独的 for 循环更快。相同的速度,也许,但不太可能。但是更快没有任何意义。尤其是在您所看到的边际上,速度的百分之几是有意义的,而处理器正在执行的其他事情会出现波动。试着颠倒测试的顺序,看看是否有区别?
      【解决方案4】:

      如果循环的顺序无关紧要,以下应该是最快的,因为您只需要一个局部变量;此外,递减计数器和边界检查是通过一条语句完成的:

      var i = foo.length;
      if(i) do { // check for i != 0
          // do stuff with `foo[i]`
      } while(--i);
      

      我通常使用的如下:

      for(var i = foo.length; i--; ) {
          // do stuff with `foo[i]`
      }
      

      它可能比以前的版本慢(post-vs pre-decrement,for vs while),但更具可读性。

      【讨论】:

        【解决方案5】:

        最快的迭代方式是减少循环中的操作。将内容从迭代中带出并最小化循环内的查找/增量,例如

        var i = arr.length;
        
        while (i--) {
           console.log("Item no "+i+" is "+arr[i]);
        }
        

        注意!通过在最新的 Safari(使用 WebKit nightly)、Chrome 和 Firefox 上进行测试,您会发现如果不是 for eachfor in(甚至更糟糕的是,任何基于它们的派生函数)。

        另外,事实证明,下面的for 循环比上面的选项稍微快一点:

        var l = arr.length;
        
        for (var i=l; i--;) {
            console.log("Item no "+i+" is "+arr[i]);
        }
        

        【讨论】:

          猜你喜欢
          • 2021-11-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-09-30
          • 2018-06-06
          • 2013-07-16
          • 2010-09-10
          • 1970-01-01
          相关资源
          最近更新 更多