基于 if-else、开关或映射的条件反射的性能

我想知道以下 javascript 中条件结构的实现的性能。

方法一:

 if(id==="camelCase"){
window.location.href = "http://www.thecamelcase.com";
}else if (id==="jsFiddle"){
window.location.href = "http://jsfiddle.net/";
}else if (id==="cricInfo"){
window.location.href = "http://cricinfo.com/";
}else if (id==="apple"){
window.location.href = "http://apple.com/";
}else if (id==="yahoo"){
window.location.href = "http://yahoo.com/";
}

方法二:

switch (id) {
case 'camelCase':
window.location.href = "http://www.thecamelcase.com";
break;
case 'jsFiddle':
window.location.href = "http://www.jsfiddle.net";
break;
case 'cricInfo':
window.location.href = "http://www.cricinfo.com";
break;
case 'apple':
window.location.href = "http://www.apple.com";
break;
case 'yahoo':
window.location.href = "http://www.yahoo.com";
break;


}

方法3

var hrefMap = {
camelCase : "http://www.thecamelcase.com",
jsFiddle: "http://www.jsfiddle.net",
cricInfo: "http://www.cricinfo.com",
apple: "http://www.apple.com",
yahoo: "http://www.yahoo.com"
};
window.location.href = hrefMap[id];

方法4

window.location.href = {
camelCase : "http://www.thecamelcase.com",
jsFiddle: "http://www.jsfiddle.net",
cricInfo: "http://www.cricinfo.com",
apple: "http://www.apple.com",
yahoo: "http://www.yahoo.com"
}[id];

方法3和方法4可能具有几乎相同的性能,但只是发送以确认。

49539 次浏览

你可以自己做 JsPerf测试。然而,一般来说,查找表是访问数据的最快方式。这将是 (3)在您的片段。而且,switch/case几乎总是比 if-else快。所以你的例子的顺序是

(3) -> (4)-> (2)-> < strong > (1)

根据这个 JSBen.ch测试,在所提供的方法(Firefox 8.0和 Chromium 15)中,switch设置是最快的。

方法3和4的速度稍慢,但几乎不明显。显然,if-elseif 方法要慢得多(FireFox 8.0)。

在 Chromium 15中进行的同样的测试并没有显示出这些方法在性能上的显著差异。事实上,if-elseif 方法似乎是 Chrome 中最快的方法。

更新

我已经运行了测试用例 再来一次,还有10个附加条目。Hrefmap (方法3和方法4)显示了更好的性能。

如果您想在函数中实现比较方法,方法3肯定会胜出: 将映射存储在一个变量中,并在稍后引用该变量,而不是重新构造它。

只是觉得我应该把这个作为一个可能的考虑因素。我偶然发现了这个关于这个问题的研究... ... http://davidbcalhoun.com/2010/is-hash-faster-than-switch-in-javascript

它考虑到了不同的引擎和浏览器。

条件逻辑的性能差异(而不仅仅是值查找)

if-else vs switch vs map of functions vs class method dispatch

我认为很多人来到这个问题,基于 if-else、开关或映射的条件反射的性能,因为他们想知道如何最好的条件 逻辑,正如标题所暗示的,而不是简单的基于键的值查找。

我的基准 与公认的答案不同,并且纠正了一些缺陷(结果表底部的进一步解释) :

  1. 测试 分支逻辑 ,即 有条件的执行流,而不是简单的查找。

  2. 随机分支。在安装过程中生成一个随机的分支密钥序列。然后用相同的顺序测试每种方法。

  3. 分支结果不可预测。对于其他分支,每个分支的逻辑结果不相同,对于同一分支的后续执行,< em > 也不相同。

  4. 一共有11个分支机构。对我来说,这个问题更适用于那么多人。如果数量少得多,那么考虑除 if-elseswitch之外的任何东西都是没有意义的。

  5. 可重用的结构在 setup 中初始化,而不是在基准代码块中初始化。

这是我在 Safari/macOS 上看到的:

接近 JSBench
if-else 100
switch 99 +
map of functions 90
class method dispatch ~ 85

我运行 同样的基准再次两倍多的分行(22)期望看到地图获得地面,我得到了大约相同的结果(虽然 class method dispatch可能做得稍微好一点)。如果我有时间,我会编写代码来生成基准代码,这样我就可以绘制出大范围的分支计数图... ... 可惜我没有。

问题示例代码中的局限性以及其他答案和注释中的基准测试

问题本身的示例代码以及 Rob W 的回答JAndy 的回答中仅用于测试值查找的基准测试代码。正如预期的那样,对于一小组键,这些基准测试显示的性能差异可以忽略不计; 任何显著的差异都可能是 JS 引擎中的一个缺陷。它们不能证明 条件逻辑的问题。

此外,正如一些人指出的那样,基准代码中还存在其他缺陷:

  • 只有当条件逻辑被执行数千次时,性能才重要。在这种情况下,不会重新初始化每个使用的数据结构。

  • 测试代码每次使用相同的分支,这有两个问题:

    • 它不反映平均成本(例如,对于 if-else 或 switch,早期的分行更便宜,晚期的分行更昂贵)。

    • 编译时或 JIT 优化可能会优化掉它,从而产生误导性的结果(因为在实际代码中,条件不会如此可预测)。

  • 每个分支每次都产生完全相同的结果。对于 Rob W 的基准,结果与输入相同!

    • 当然,一个地图将执行良好的这种用法。这就是他们的设计目的!

    • 如果有条件逻辑,其中每个分支的逻辑每次都产生完全相同的结果,则应考虑使用 备忘录