为什么两次调用string.charCodeAt()的速度要快于从未达到的if中的另一个调用?

时间:2019-01-13 07:23:46

标签: javascript performance v8

我在nodejs / chrome / v8中发现了一个奇怪的行为。似乎这段代码:

var x = str.charCodeAt(5);
x = str.charCodeAt(5);

比这快

var x = str.charCodeAt(5); // x is not greater than 170
if (x > 170) {
  x = str.charCodeAt(5);
}

起初,我也许比较起来比实际的第二次调用要贵,但是当if块中的内容未调用str.charCodeAt(5)时,性能与一次调用相同。

这是为什么?我最好的猜测是v8正在优化/取消优化某些东西,但我不知道如何准确地找出这一点或如何防止这种情况发生。

这里是jsperf的链接,至少在我的机器上很好地演示了此行为: https://jsperf.com/charcodeat-single-vs-ifstatment/1

jsperf


背景:之所以找到这个原因,是因为我试图优化babel-parser内部的令牌读取。

我测试过,str.charCodeAt()的速度是str.codePointAt()的两倍,因此尽管我可以替换以下代码:

var x = str.codePointAt(index);

使用

var x = str.charCodeAt(index);
if (x >= 0xaa) {
  x = str.codePointAt(index);
}

但是由于上述行为,第二个代码并没有给我任何性能上的优势。

1 个答案:

答案 0 :(得分:3)

V8开发人员在这里。正如Bergi指出的那样:请勿使用微基准来做出此类决定,因为它们会误导您。

看到每秒数亿次操作的结果通常意味着优化的编译器能够消除所有代码,并且您正在测量空循环。您必须查看生成的机器代码,以查看是否正在发生这种情况。

当我将四个片段复制到一个小的独立文件中以进行本地调查时,我看到了截然不同的性能结果。两者中哪一个更接近您的实际用例?不知道。而且,这种进一步分析毫无意义。

一般而言,分支比直线代码(在所有CPU上以及所有编程语言中)慢。因此(除了消除死代码和其他微基准测试陷阱之外),如果“两次”案例实际上比两个“如果”案例中的任何一个都快,我也不会感到惊讶。也就是说,调用String.charCodeAt可能足以抵消这种影响。