为什么Firefox执行Javascript比其他浏览器快得多

4

我正在Firefox,Chrome和Safari下对以下JavaScript代码片段进行性能测试

var f = function(x) {
 return Math.sin(x);
}

function testSpeed() {
 console.log("test started, please hold on...");
 var time = Date.now();
 for(var i = 0; i < 1000; i ++) {
  for(var x = 1; x < 200000; x ++) {
   f(x);//replace by Math.sin(x) here
  }
 }
 console.log("total time = " + ((Date.now() - time) / 1000.0));
}

testSpeed();

结果如下:
  • 在Firefox下为0.12秒,当我将f(x)调用替换为Math.sin(x)时相同。
  • 在Chrome下为5.2秒,当我将f(x)调用替换为Math.sin(x)时相同。
  • 在Safari下为7.12秒,但令人惊讶的是,当我将f(x)调用替换为Math.sin(x)时,只有0.56秒
  • 这使得Firefox比Chrome快约50倍,比Safari快约70倍,是否有任何已知原因?
    此外,在Safari下,为什么直接调用Math.sin(x)f(x)的调用相比会有巨大的差异(约快13倍)?

    有趣的是,即使是Edge也比Chrome更快。得分:0.287。 - Abdullah Mallik
    2
    当你完全删除 f(x) 的调用或者删除 f 函数的主体时,速度会是多少?由于它没有任何影响,引擎可以合理地将其消除。 - Ry-
    1
    @Ryan 在没有 f(x) 的情况下,Firefox 保持了 0.12 秒的执行时间,Chrome 竟然降至 0.18 秒,Safari 则为 0.54 秒,由于某种原因,在 Chrome 和 Safari 下,函数调用会极大地影响性能。 - ALTN
    4
    函数调用会影响所有浏览器的性能。你所看到的是Firefox意识到该函数没有副作用,并且你没有使用其返回值,因此根本没有调用该函数。Safari似乎也意识到Math.sin是纯函数,并在直接使用它时执行相同的优化,但在这种情况下没有扩展到f。Chrome可能会认识到你正在尝试进行基准测试,并避免在基准测试函数中消除死代码,但这只是一个猜测。 - Ry-
    1
    通过对返回值进行读取并在最后记录,@Ryan 进行了精彩的分析,Firefox 的响应时间提高到了 4.1 秒。我会写一个答案! - ALTN
    刚在Firefox 75和Chrome 81中进行了测试。使用Math.sin(x)代替函数调用进行测试。奇怪的是,Chrome显示0.186秒,而Firefox则显示41.253秒。 但是,如果我将Math.sin(x)更改为let a=12;let b=423;let c=a+b,Chrome只需要0.179秒,而Firefox需要0.258秒。 另一方面,如果我测试从DOM读取(document.getElementsByClassName('round')[0].click()),Firefox在这种情况下执行速度比较快,快35%。我的CPU是Q6600,我正在使用Windows 7 64位。我想知道其他人是否有类似的结果。 - teg_brightly
    1个回答

    3
    在评论中,Ryan 指出 Firefox 实际上注意到该函数没有任何副作用,其返回值也未被使用,因此可以安全地省略该调用。将代码更改如下所示,则使 Firefox 的执行时间增加到 4.1 秒。

    var f = function(x) {
     return Math.sin(x);
    }
    
    function testSpeed() {
     console.log("test started, please hold on...");
     var time = Date.now();
     var y;
     for(var i = 0; i < 1000; i ++) {
      for(var x = 1; x < 200000; x ++) {
       y = f(x);
      }
     }
     console.log("total time = " + ((Date.now() - time) / 1000.0) + "   " + y);
    }
    
    testSpeed();

    请注意,在嵌套循环末尾不记录y时,Firefox仍然注意到未使用的返回值并省略了函数调用。当y保持未使用时,执行时间保持在0.12秒。
    至于为什么在调用Math.sin(x)时Safari运行得更快,我将引用Ryan的评论:
    “Safari似乎也认识到Math.sin是纯的,并在直接使用它时执行相同的优化,但在这种情况下没有将其扩展到f。”

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