查看其他答案中的解决方案,我发现根据过去的经验,我发现一些对性能不利的事情。
我已经在不同的浏览器中测试了多种解决方案,下面是我的结果(ymmv),根据每个浏览器中最快的操作进行标准化。
这是 2021 年 5 月 5 日的结果
Test |
Chrome |
Firefox |
Opera |
Edge |
Brave |
Node |
1.0 time |
15 ms |
14 ms |
17 ms |
17 ms |
16 ms |
14 ms |
if-immediate |
1.00 |
1.00 |
1.00 |
1.00 |
1.00 |
1.00 |
if-indirect |
2.20 |
1.21 |
2.06 |
2.18 |
2.19 |
1.93 |
switch-immediate |
2.07 |
1.43 |
1.71 |
1.71 |
2.19 |
1.93 |
switch-range |
3.60 |
2.00 |
2.47 |
2.65 |
2.88 |
2.86 |
switch-range2 |
2.07 |
1.36 |
1.82 |
1.71 |
1.94 |
1.79 |
switch-indirect-array |
2.93 |
1.57 |
2.53 |
2.47 |
2.75 |
2.50 |
array-linear-switch |
2.73 |
3.29 |
2.12 |
2.12 |
2.38 |
2.50 |
array-binary-switch |
5.80 |
6.07 |
5.24 |
5.24 |
5.44 |
5.37 |
2021 年的测试在 Windows 10 64 位、以下版本上进行:铬90.0.4430.212, 火狐浏览器89.0b13, 歌剧 76.0.4017.123, 边缘90.0.818.62, 勇敢者 1.24.85, and 节点16.1.0(在 WSL 下运行)
苹果不更新了Windows 版 Safari,所以仍然是5.1.7。我在这次测试中将其更改为Brave。
以下是 2012 年 9 月 4 日的结果,用于历史比较:
Test |
Chrome |
Firefox |
Opera |
MSIE |
Safari |
Node |
1.0 time |
37 ms |
73 ms |
68 ms |
184 ms |
73 ms |
21 ms |
if-immediate |
1.0 |
1.0 |
1.0 |
2.6 |
1.0 |
1.0 |
if-indirect |
1.2 |
1.8 |
3.3 |
3.8 |
2.6 |
1.0 |
switch-immediate |
2.0 |
1.1 |
2.0 |
1.0 |
2.8 |
1.3 |
switch-range |
38.1 |
10.6 |
2.6 |
7.3 |
20.9 |
10.4 |
switch-range2 |
31.9 |
8.3 |
2.0 |
4.5 |
9.5 |
6.9 |
switch-indirect-array |
35.2 |
9.6 |
4.2 |
5.5 |
10.7 |
8.6 |
array-linear-switch |
3.6 |
4.1 |
4.5 |
10.0 |
4.7 |
2.7 |
array-binary-switch |
7.8 |
6.7 |
9.5 |
16.0 |
15.0 |
4.9 |
2012年的测试是在Windows 7 32位以下版本上进行的:铬21.0.1180.89m, 火狐15.0, 歌剧 12.02, MSIE 9.0.8112, Safari 5.1.7. Node在 Linux 64 位机器上运行,因为 Windows 的 Node 上的计时器分辨率是 10 毫秒,而不是 1 毫秒。
if-立即
这是所有测试环境中最快的方法,除了......drumroll微星! (惊讶,惊讶)。
这是推荐的实施方式。
if (val < 1000) { /*do something */ } else
if (val < 2000) { /*do something */ } else
...
if (val < 30000) { /*do something */ } else
if-间接
这是一个变体switch-indirect-array
但与if
-语句代替,并且在所有测试的引擎中速度更快。
2021 年,它比最快的测试慢了 20-120%(2012 年:0-280%)。 Chrome 在 2021 年 (2.20) 花费的时间比 2012 年 (1.2) 更长
values=[
1000, 2000, ... 30000
];
if (val < values[0]) { /* do something */ } else
if (val < values[1]) { /* do something */ } else
...
if (val < values[29]) { /* do something */ } else
立即切换
当您可以进行计算以获得索引时,这很有效。
2021 年,速度比 2012 年慢 40-120%(2012 年:0-180%)if-immediate
,除了 MSIE,它实际上是最快的。
switch (Math.floor(val/1000)) {
case 0: /* do something */ break;
case 1: /* do something */ break;
...
case 29: /* do something */ break;
}
开关范围
它很慢,因为引擎必须为每种情况比较两次值。
2021 年,它比最快的测试慢了 1-2.6 倍(2012 年:1.6-38)倍。
Chrome 的改进最大,从 38 到 3.6,但仍然是经过测试的最慢的引擎。
switch (true) {
case (0 <= val && val < 1000): /* do something */ break;
case (1000 <= val && val < 2000): /* do something */ break;
...
case (29000 <= val && val < 30000): /* do something */ break;
}
开关范围2
这是一个变体switch-range
但每个案例仅进行一次比较,因此速度更快。
case 语句的顺序很重要,因为引擎将按源代码顺序测试每个 caseECMAScript 2020 13.12.9 https://262.ecma-international.org/11.0/#sec-runtime-semantics-caseblockevaluation
2021 年,它比最快的测试慢了 36-107%,但 2012 年却慢了 1-31 倍。在这次测试中表现最差的仍然是 Chrome,但它已经从 32 倍提高到了 2 倍。
switch (true) {
case (val < 1000): /* do something */ break;
case (val < 2000): /* do something */ break;
...
case (val < 30000): /* do something */ break;
}
开关间接数组
在此变体中,范围存储在数组中。
2021 年,它比最快的测试慢了 57-193%(2012 年:3-35 倍)。
所有测试引擎的性能都有所提高,虽然 Chrome 仍然是最慢的,但它已从 35 提高到 2.93。
values=[1000, 2000 ... 29000, 30000];
switch(true) {
case (val < values[0]): /* do something */ break;
case (val < values[1]): /* do something */ break;
...
case (val < values[29]): /* do something */ break;
}
数组线性搜索
在此变体中,范围存储在数组中。
2021 年,它比最快的测试慢了 57-193%(2012 年:3-35 倍)。
所有测试引擎的性能都有所提高,虽然 Chrome 仍然是最慢的,但它已从 35 提高到 2.93。
values=[1000, 2000 ... 29000, 30000];
for (sidx=0, slen=values.length; sidx < slen; ++sidx) {
if (val < values[sidx]) break;
}
switch (sidx) {
case 0: /* do something */ break;
case 1: /* do something */ break;
...
case 29: /* do something */ break;
}
数组二进制开关
这是一个变体array-linear-switch
但使用二分搜索。
不幸的是它比线性搜索慢。我不知道这是我的实现还是线性搜索更优化。也可能是密钥空间太小。
2021 年,这一速度慢了 4-5 倍(2012 年:4-16)倍。不使用.
values=[0, 1000, 2000 ... 29000, 30000];
while(range) {
range = Math.floor( (smax - smin) / 2 );
sidx = smin + range;
if ( val < values[sidx] ) { smax = sidx; } else { smin = sidx; }
}
switch (sidx) {
case 0: /* do something */ break;
...
case 29: /* do something */ break;
}
结论
如果性能很重要,请使用if
- 陈述或switch
,具有立即值。