为什么JavaScript正则表达式文字执行在分配给变量时较慢?

为什么JavaScript正则表达式文字执行在分配给变量时较慢?,javascript,regex,performance,Javascript,Regex,Performance,我的问题与前一个问题有关,前一个问题说以下两种方式的速度几乎相同 但当我实际使用循环计数1000000测试它时,似乎有一个一致的性能。虽然我认为示例1应该更快,但结果证明它比示例2慢 测试页面的结果如下所示。例如1,执行时间为:[20.27,19.82,16.17],但例如2,执行时间较短:[18.57,15.48,15.14] 结果让我很困惑。有人能告诉我原因吗 var str = "Hello World"; // Example 1 var regExp1 = /[aeiou]+/gi;

我的问题与前一个问题有关,前一个问题说以下两种方式的速度几乎相同

但当我实际使用循环计数1000000测试它时,似乎有一个一致的性能。虽然我认为示例1应该更快,但结果证明它比示例2慢

测试页面的结果如下所示。例如1,执行时间为:[20.27,19.82,16.17],但例如2,执行时间较短:[18.57,15.48,15.14]

结果让我很困惑。有人能告诉我原因吗

var str = "Hello World";
// Example 1
var regExp1 = /[aeiou]+/gi;
for(var i = 0; i < 1000; ++i)
  regExp1.exec(str);
// Example 2
for(var j = 0; j < 1000; ++j)
  /[aeiou]+/gi.exec(str);
var str=“你好世界”;
//例1
var regExp1=/[aeiou]+/gi;
对于(变量i=0;i<1000;++i)
regExp1.exec(str);
//例2
对于(var j=0;j<1000;++j)
/[aeiou]+/gi.exec(str);
它必须慢一点

因为每次在循环中进行新的迭代时,都会在执行正则表达式之前重新计算它

这会导致较小的延迟,但对于较大的循环,会有时间差

在第一个示例中,已经对其进行了定义和评估

因此,所需的唯一时间是执行。

显示的是操作/秒,而不是执行时间。因此,值越高,代码运行得越快

第一个版本更快,而不是更慢。通过在一个测试集中运行不同数量的迭代,您得到了令人困惑的结果20.27ops/s比18.57ops/s快


毫无疑问,在单独的变量中缓存regexp要比在每次迭代中编译快(V8 VM缓存已编译的regex,但显然没有显式缓存那么有效)。

这是针对原始问题的扩展测试(从我的一次运行开始,第一次是针对“Hello World!”,第二个加上“a”)

let str=“你好,世界!”;//备选“a”
//循环中的文字(392毫秒,384毫秒)
对于(设i=0;i<10000;++i){
对于(设j=0;j<1000;++j)
/[aeiou]+/gi.exec(str);
}
//环路中的构造(1747毫秒、1677毫秒)
对于(设i=0;i<10000;++i){
对于(设j=0;j<1000;++j)
新的RegExp(“[aeiou]+”,“gi”).exec(str);
}
//缓存文字(335毫秒,252毫秒,最快)
对于(设i=0;i<10000;++i){
设regex=/[aeiou]+/gi;
对于(设j=0;j<1000;++j)
regex.exec(str);
}
//缓存构造(351毫秒、270毫秒)
对于(设i=0;i<10000;++i){
设regex=newregexp(“[aeiou]+”,“gi”);
对于(设j=0;j<1000;++j)
regex.exec(str);
}
所以我们可以观察到

  • 文字总是比构造函数版本快:
  • 缓存版本总是比内联版本快
  • 与循环内部的构造相比,循环内部的文本和循环外部的文本之间的差异很小
  • 循环中文字的开销非常小,因此它只与短字符串上的多次迭代有关(在更复杂的情况下,可读性与运行时性能)
以下段落可以部分解释这一观察结果:

文本表示法在计算正则表达式时提供正则表达式的编译。当正则表达式保持不变时,使用文字表示法。例如,如果使用文字符号来构造循环中使用的正则表达式,则不会在每次迭代中重新编译正则表达式


虽然在加载过程中编译了所有文本,但仍然需要从编译后的文本构造一个RegExp对象,这会导致循环中文本的开销,与使用循环中构造函数的运行时编译相比,这个开销很小

您是如何计时的?我认为,为了使基准测试有意义,它应该只测量对
exec()
的调用,而不是其他任何东西(与正则表达式的性能无关的“其他任何东西”)。您为执行测试提供的基准测试测量每秒的操作数,而不是经过的时间。当我运行测试时,我发现ops/sec比示例1中的更快,这意味着示例1中的方法实际上比示例2中的方法更快。
let str = "Hello World!"; // Alternative "a" 

// Literal in loop         (392 ms, 384 ms)
for (let i = 0; i < 10000; ++i) {
    for(let j = 0; j < 1000; ++j)
        /[aeiou]+/gi.exec(str);
}

// Construction in loop    (1747 ms, 1677 ms)
for (let i = 0; i < 10000; ++i) {
    for(let j = 0; j < 1000; ++j)
        new RegExp("[aeiou]+", "gi").exec(str);
}

// Cached literal          (335 ms, 252 ms, fastest)
for (let i = 0; i < 10000; ++i) {
    let regex = /[aeiou]+/gi;
    for(let j = 0; j < 1000; ++j)
        regex.exec(str);
}

// Cached construction     (351 ms, 270 ms)
for (let i = 0; i < 10000; ++i) {
    let regex = new RegExp("[aeiou]+", "gi");
    for(let j = 0; j < 1000; ++j)
        regex.exec(str);
}