【问题标题】:Why JavaScript regex literal execution is slower when it is assigned to a variable?为什么将 JavaScript 正则表达式文字分配给变量时执行速度较慢?
【发布时间】:2019-12-29 05:13:19
【问题描述】:

我的问题与之前的Stackoverflow post 有关,它说以下两种方式的速度几乎相同。

但是当我实际使用循环计数 1000000 对其进行测试时,似乎有一致的性能。虽然我预计示例 1 应该更快,但结果却比示例 2 慢。

测试页面的结果是here。例如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);

【问题讨论】:

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

标签: javascript regex performance


【解决方案1】:

它必须更慢。

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

这会导致很小的延迟,但如果循环很大,则会有时间差

在第一个示例中,它已经被定义和评估。

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

【讨论】:

    【解决方案2】:

    jsperf.com 显示的是 ops/sec,而不是执行时间。因此值越高,代码越快。

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

    毫无疑问 - 将正则表达式缓存在一个单独的变量中会比在每次迭代中编译它更快(V8 VM 缓存已编译的正则表达式,但显然不如显式执行它的效率高)。

    【讨论】:

      【解决方案3】:

      这是对原始问题的扩展测试(我的一次运行时间,第一次是“Hello World!”,第二次是“a”)

      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);
      }
      

      所以我们可以观察到

      • 文字总是比构造函数版本快:
      • 缓存版本总是比内联版本快
      • 与循环内的构造相比,循环内的文字和循环外的文字之间的差异很小
      • 循环中文字的开销非常小,仅与短字符串的多次迭代相关(在更复杂的情况下,可读性与运行时性能)

      the MDN RegExp reference 的以下段落可以部分解释这一观察结果:

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

      似乎虽然所有文字都是在加载期间编译的,但仍然需要从编译后的文字构造一个 RegExp 对象,这导致循环中文字的开销与使用循环中的构造函数的运行时编译相比很小

      【讨论】:

        猜你喜欢
        • 2014-07-20
        • 1970-01-01
        • 2013-01-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-09
        • 2010-11-17
        相关资源
        最近更新 更多