JavaScript性能:为什么循环遍历数组并检查每个值比使用indexOf、search和match更快?

18

这对我来说是一个巨大的惊喜,我想要理解这个结果。我在 jsperf测试 中进行了一项测试,基本上是检查一个字符串(它是URL的一部分,我想要检查)并检查其中是否包含4个项目(实际上,这些项目都包含在字符串中)。

它有5种检查方式:

  1. 普通的indexOf;
  2. 拆分字符串,然后使用indexOf;
  3. 正则表达式搜索;
  4. 正则表达式匹配;
  5. 拆分字符串,循环遍历项目数组,然后检查是否与应该匹配的内容相匹配

令我非常惊讶的是,在Chrome 21中,第5种方式是最快的。这是我无法解释的。

在Firefox 14中,普通的indexOf是最快的,这一点我可以相信。


1
其实我觉得这很有道理...你只迭代了一次字符串而不是四次。当然,indexOf会更早地退出,但我可以想象字符串太短了,以至于这没有影响(虽然这并不能解释Firefox的结果 :-/)。 - Felix Kling
1
很好的问题。+1,特别是你制作了一个测试用例。 - starbeamrainbowlabs
@FelixKling,您说的一次迭代字符串是什么意思?它确实需要通过字符串4次来评估其中的每个4个项目... - João Pinto Jerónimo
1
其实后来我意识到我想说的是迭代数组... 我在考虑你的测试用例4和5(4是你遍历数组的那个,5是你使用indexOf的那个)。indexOf总是要遍历整个数组直到找到匹配项,而你这样做了四次,所以与你的while循环只需要一次相比,你可能要遍历整个数组四次。第一个测试用例也是如此(字符串迭代四次)。 - Felix Kling
我创建了http://jsperf.com/finding-components-of-a-url/4,它增加了一些细节并提供了一致的布尔结果。 - slevithan
2个回答

9
我很惊讶,但Chrome使用高度优化的JavaScript引擎v8,可以使用各种技巧。Google的工程师可能拥有最大量的JavaScript代码来测试他们实现的性能。所以我猜测发生了以下情况:
  1. 编译器注意到数组是字符串数组(类型可以在编译时确定,无需运行时检查)。
  2. 在循环中,由于您使用了 === ,因此可以使用内置的CPU操作码来比较字符串( repe cmpsb )。因此,没有调用任何函数(与任何其他测试用例不同)。
  3. 在第一次循环之后,所有重要内容(数组、要进行比较的字符串)都在CPU缓存中。局部性规则一切。
所有其他方法都需要调用函数,并且正则表达式版本可能存在局部性问题,因为它们构建解析树。

3

有趣的是正则表达式字面量,但组合的正则表达式不作为替代品,因为我想最终得到4个变量,这些变量评估为真或假(或0或1),无论字符串是否被找到。 - João Pinto Jerónimo

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