12

我使用 JavaScript 解析器生成器JISON为我的用户创建的一些脚本创建解析器。最近我注意到 Firefox 上的解析过程比我的页面支持的任何其他浏览器(IE10、最新的 Chrome 和 Opera)慢很多。

在深入研究了生成的解析器的源代码之后,我将问题缩小到一行代码,它执行一些正则表达式来标记要解析的代码。当然,这条线经常被执行。

我用一些随机字符串(大约 1300 个字符长)和一个非常通用的正则表达式创建了一个小测试用例。此测试用例测量执行正则表达式 10000 次所需的平均时间(JSFiddle 上的工作示例):

$(document).ready(function() {
    var str = 'asdfasdfa asdfasdf asdf asdf asdfasödlfkja asldfkj asdölkfj aslödkjf aösldkfj ölkasjd flöaksjdf löask dfjkasdfasdfa asdfasdf asdf asdf asdfasödlfkja asldfkj asdölkfj aslödkjf aösldkfj ölkasjd flöaksjdf löask dfjkasdfasdfa asdfasdf asdf asdf asdfasödlfkja asldfkj asdölkfj aslödkjf aösldkfj ölkasjd flöaksjdf löask dfjkasdfasdfa asdfasdf asdf asdf asdfasödlfkja asldfkj asdölkfj aslödkjf aösldkfj ölkasjd flöaksjdf löask dfjkasdfasdfa asdfasdf asdf asdf asdfasödlfkja asldfkj asdölkfj aslödkjf aösldkfj ölkasjd flöaksjdf löask dfjkasdfasdfa asdfasdf asdf asdf asdfasödlfkja asldfkj asdölkfj aslödkjf aösldkfj ölkasjd flöaksjdf löask dfjkasdfasdfa asdfasdf asdf asdf asdfasödlfkja asldfkj asdölkfj aslödkjf aösldkfj ölkasjd flöaksjdf löask dfjkasdfasdfa asdfasdf asdf asdf asdfasödlfkja asldfkj asdölkfj aslödkjf aösldkfj ölkasjd flöaksjdf löask dfjkasdfasdfa asdfasdf asdf asdf asdfasödlfkja asldfkj asdölkfj aslödkjf aösldkfj ölkasjd flöaksjdf löask dfjkasdfasdfa asdfasdf asdf asdf asdfasödlfkja asldfkj asdölkfj aslödkjf aösldkfj ölkasjd flöaksjdf löask dfjkasdfasdfa asdfasdf asdf asdf asdfasödlfkja asldfkj asdölkfj aslödkjf aösldkfj ölkasjd flöaksjdf löask dfjkasdfasdfa asdfasdf asdf asdf asdfasödlfkja asldfkj asdölkfj aslödkjf aösldkfj ölkasjd flöaksjdf löask dfjkasdfasdfa asdfasdf asdf asdf asdfasödlfkja asldfkj asdölkfj aslödkjf aösldkfj',
        regex = new RegExp('^([0-9])+'),
        durations = [],
        resHtml = 'Durations:',
        totalDuration = 0,
        matches, start;

    // Perform "timing test" 10 times to get some average duration
    for (var i = 0; i < 10; i++) {
        // Execute regex 10000 times and see how long it takes
        start = window.performance.now();
        for (var j = 0; j < 10000; j++) {
            regex.exec(str);
        }
        durations.push(window.performance.now() - start);
    }

    // Create output string and update DIV
    for (var i = 0; i < durations.length; i++) {
        totalDuration += durations[i];
        resHtml += '<br>' + i + ': ' + (parseInt(durations[i] * 100, 10) / 100) + ' ms';
    }
    resHtml += '<br>==========';
    resHtml += '<br>Avg: ' + (parseInt((totalDuration / durations.length) * 100, 10) / 100) + ' ms';

    $('#result').html(resHtml);
});

以下是我机器上的测试结果:

Firefox 24 : 10000 次正则表达式执行的平均时间在370 和 450 毫秒之间
Chrome 30、Opera 17、IE 10:平均时间在0.3 和 0.6 毫秒之间

如果要测试的字符串变大,这种差异会变得更大。一个 6000 字符长的字符串将 Firefox 中的平均时间增加到~ 1.5 秒(!),而其他浏览器仍然需要~ 0.5 毫秒(!)JSFiddle 上的 6000 个字符的工作示例)。

为什么 Firefox 和所有其他浏览器之间存在如此大的性能差异,我可以无论如何改进它吗?

请注意,我无法自行调整已执行的正则表达式,因为它们主要由解析器生成器生成,我不想手动更改构建的解析器代码。

4

1 回答 1

2

RegExp捕获分组让您:

/^[0-9]+/和/或/^(?:[0-9])+/和/或/^([0-9]+)/比 快几个数量级/^([0-9])+/。它们应该是可行的替代方案。

我希望捕获组会稍微慢一些,但它慢得多让我感到惊讶。然而,慢速版本有可能创建大量捕获,而其他版本则没有,因此这似乎是一个重要的区别。

不科学的 jsperf

您可能想提交一个错误

于 2013-10-30T12:56:38.320 回答