Javascript 开关与 if...else if...else

IT技术 javascript cross-browser conditional
2021-01-13 21:12:47

伙计们,我有几个问题:

  1. JavaScript 中的switch语句和if...else?之间是否存在性能差异
  2. 如果是为什么?
  3. 浏览器之间switch行为是否if...else不同?(火狐、IE、Chrome、Opera、Safari)

问这个问题的原因似乎是我switch在 Firefox 中使用大约 1000 个案例语句获得了更好的性能


编辑 不幸的是,这不是我的代码,Javascript 是从编译的库在服务器端生成的,我无法访问该代码。调用生成 javascript 的方法

CreateConditionals(string name, string arrayofvalues, string arrayofActions)

注意arrayofvalues是逗号分隔的列表。

它产生的是

function [name] (value) {
  if (value == [value from array index x]) {
     [action from array index x]
  }
}

注意: where [name]= 传入服务器端函数的名称

现在我把函数的输出改成一个TextArea,写了一些JavaScript代码通过函数解析,转换成一组case语句。

最后我运行该函数,它运行良好,但在 IE 和 Firefox 中的性能不同。

6个回答

一般性回答:

  1. 是的,通常。
  2. 在此处查看更多信息
  3. 是的,因为每个都有不同的 JS 处理引擎,但是,在下面的站点上运行测试时,开关总是在大量迭代中执行 if、elseif。

测试地点

@LogicDaemon - IIRC 是一些 oRielly 文本框的链接,这些文本框进入了一些深入的 JS 性能考虑/讨论
2021-03-16 21:12:47
如果您想了解何时使用哪些条件的 TLDR,请直接链接到文章中的某个部分,该部分解决了该问题:oreilly.com/server-administration/excerpts/even-faster-websites/...
2021-03-27 21:12:47
@Tommy «在这里查看更多信息» 给出了 404,那是什么?
2021-03-27 21:12:47
此描述中是否显示了任何可量化的内容?它读起来像是很多“最佳实践/过早优化”猜想。它也是 7 年前写的,所以这段时间 javascript 优化发生了巨大的变化。在编译语言中,这三个操作之间的性能差异“几乎从来没有足够的关注”。不要费心优化不会影响实际性能的东西。优化可读性。
2021-04-02 21:12:47
@Tommy 好文章,感谢分享。但是文章指出,JS 中的switchif/then语句之间的性能差异可以忽略不计文章指出这是由于switch优化不一以及不同 JS 引擎运行的不同方式造成的。引用:Since most JavaScript engines don’t have such optimizations, performance of the switch statement is mixed.
2021-04-03 21:12:47

有时两者都不使用会更好。例如,在“调度”情况下,Javascript 让您以完全不同的方式做事:

function dispatch(funCode) {
  var map = {
    'explode': function() {
      prepExplosive();
      if (flammable()) issueWarning();
      doExplode();
    },

    'hibernate': function() {
      if (status() == 'sleeping') return;
      // ... I can't keep making this stuff up
    },
    // ...
  };

  var thisFun = map[funCode];
  if (thisFun) thisFun();
}

通过创建对象来设置多路分支有很多优点。您可以动态添加和删除功能。您可以从数据创建调度表。您可以以编程方式检查它。您可以使用其他函数构建处理程序。

有一个函数调用的额外开销以获得等效的“案例”,但是哈希查找的优势(当有很多案例时)可以找到特定键的函数。

你的策略很好,我经常使用它。但正如@Michael Geary stackoverflow.com/a/45336805/5936119所指出的,映射变量必须在调度上下文之外声明,否则它将始终被重新评估。
2021-03-21 21:12:47
@DanielSantana 是真的,但我怀疑这太贵了。特别是,一旦函数最初被解析,代码本身就不需要重新生成,因为文本是静态的。
2021-04-13 21:12:47

aswitcha 之间的性能差异if...else if...else很小,它们基本上做同样的工作。它们之间可能会产生影响的一个区别是要测试的表达式只switch偶尔计算一次,它会为每个if. 如果计算表达式的成本很高,那么执行一次当然比执行一百次要快。

这些命令(以及一般的所有脚本)的实现差异在浏览器之间存在很大差异。相同的代码在不同的浏览器中表现出相当大的性能差异是很常见的。

由于您几乎无法在所有浏览器中对所有代码进行性能测试,因此您应该选择最适合您正在执行的工作的代码,并尝试减少已完成的工作量,而不是优化其完成方式。

Pointy 的回答建议使用对象文字作为switchif/的替代else我也喜欢这种方法,但是map每次dispatch调用函数时,答案中的代码都会创建一个新对象

function dispatch(funCode) {
  var map = {
    'explode': function() {
      prepExplosive();
      if (flammable()) issueWarning();
      doExplode();
    },

    'hibernate': function() {
      if (status() == 'sleeping') return;
      // ... I can't keep making this stuff up
    },
    // ...
  };

  var thisFun = map[funCode];
  if (thisFun) thisFun();
}

如果map包含大量条目,这会产生大量开销。最好只设置一次动作映射,然后每次都使用已经创建的映射,例如:

var actions = {
    'explode': function() {
        prepExplosive();
        if( flammable() ) issueWarning();
        doExplode();
    },

    'hibernate': function() {
        if( status() == 'sleeping' ) return;
        // ... I can't keep making this stuff up
    },
    // ...
};

function dispatch( name ) {
    var action = actions[name];
    if( action ) action();
}

除了语法之外,可以使用生成它的树来实现 switch O(log n),而if/else必须使用O(n)过程方法来实现更常见的是,它们都是按程序处理的,唯一的区别是语法,而且这真的很重要——除非你静态输入 10k 个 if/else 案例?

哦,我不知道。这在 C 中是不可能的,afaik。那里只允许使用常量表达式。所以我认为它在 JS 中是一样的。
2021-03-14 21:12:47
7 年后......我不知道树的实现是如何可能的,除非是在常量数值的情况下)。
2021-03-23 21:12:47
3.5 年后... @Ed Staub 当然这里就是这种情况。Switch 语句与常量一起使用。无论是数字还是其他任何东西,都可以枚举它们,因此可以构造一棵树。
2021-04-02 21:12:47
@trollkotze 虽然常量是最常见的,但 case 子句可以是任何表达式。例如参见stackoverflow.com/questions/3463833/...
2021-04-05 21:12:47