我该如何对 JavaScript 代码进行基准测试?

132

是否有一个可以帮助我基准测试JavaScript代码的软件包?我不是指像Firebug这样的工具。

我需要比较两个不同的JavaScript函数,我非常熟悉Perl的Benchmark(Benchmark.pm)模块,我正在寻找类似于JavaScript的东西。

JavaScript基准测试的重点是否过分了?我能否只计时一次运行这些函数并得出结论?


似乎是重复的: http://stackoverflow.com/search?q=javascript+profiler - steamer25
可能是如何对JavaScript代码进行性能测试?的重复问题。 - John Slegers
我知道这不是万无一失的,但还是相关的:有时你只想知道如何测量函数执行所需的时间。参考链接:https://dev59.com/3XRC5IYBdhLWcg3wYf8p#15641427。 - Skippy le Grand Gourou
1
你可以在这里找到一个好的JavaScript基准测试工具:http://jsben.ch。 - EscapeNetscape
8个回答

134

只需要简单的方式。

console.time('test');
console.timeEnd('test');

10
这应该是被接受的答案。有时使用第三方服务并不方便,只使用简单内置功能就很好。 - brainbag
4
这个问题涉及到基准测试,这不仅仅是简单地计时代码运行的时间。如果所考虑的代码不到1毫秒,控制台计时器也就不再有用了(它们的分辨率上限为1毫秒)。请注意,翻译过程中我会尽力使内容通俗易懂,但不会改变原意。 - broofa
您可能还想在测试套件中运行基准测试,这需要访问计时器值。 - Robin Goupil
正确答案! - sproketboy

125

jsperf.com 是测试JS性能的首选网站,建议从这里开始。如果您需要一个从命令行或脚本运行自己测试的框架,请使用 Benchmark.js,这是jsperf.com所构建的库。

注意: 所有测试Javascript代码的人应该了解“微基准测试”的缺陷(它们是针对特定功能或操作而不是基于真实世界代码模式的更复杂测试的小型测试)。这样的测试可能有用,但由于现代JS运行时的运作方式,易于产生不准确的结果。观看Vyacheslav Egorov关于性能和基准测试的演讲可以帮助您了解这些问题的性质。

编辑:删除了有关我的JSLitmus工作的引用,因为它已不再相关或有用。


3
更新:只需使用jsperf.com-它已经得到了很大改善,并且非常适合这种情况。 jslitmus仍然可用,但已经很长时间没有进行主动开发。 (简化版翻译)使用jsperf.com进行性能测试更好,jslitmus也可以使用但不再活跃开发。 - broofa
这是优秀的答案。+1 - Justin Force
1
我想使用jsperf,但它似乎是在计算代码在一段时间内可以运行多少次,而不是计时N个循环的实际调用。我希望他们有选择的选项。 - Jeach
1
@Jeach - jsperf 给出的是“每秒操作次数”。只需将该值乘以您的代码运行时间(以秒为单位)即可。 - broofa
9
更新:jsperf网站已经下线,目前未知何时恢复。有关更多信息,请参阅此Github讨论串。 - James G.
显示剩余3条评论

81

在这里,我为大家提供一个快速计时器的代码,或许会对某些人有用:

var timer = function(name) {
    var start = new Date();
    return {
        stop: function() {
            var end  = new Date();
            var time = end.getTime() - start.getTime();
            console.log('Timer:', name, 'finished in', time, 'ms');
        }
    }
};

理想情况下,它应该放在一个类中,而不是像我上面的示例那样作为全局变量使用。使用它非常简单:
var t = timer('Some label');
// code to benchmark
t.stop(); // prints the time elapsed to the js console

7
这里很好地运用了闭包。 - Dandy
15
为了获得更准确的结果,可以使用performance.now()而不是Date()。 https://developer.mozilla.org/zh-CN/docs/Web/API/Performance/now - thormeier
正是我所需要的 - 一个 timeIt()。 - Gishu
1
TypeScript版本:https://pastebin.com/gCs9CB5F - Alexander Taylor
1
对于node.js,您可以使用process.hrtime()来获取纳秒分辨率。 - Xeoncross
你也可以调用 Date.now() 来获取当前的 Unix 时间,而不是先调用 new Date() 然后再调用 getTime() - AlienKevin

38

只需要对每个函数进行多次迭代即可。一次迭代可能不够,但根据您的功能复杂程度,大约需要100或甚至1,000次迭代才能完成工作。

如果您想查看哪些部分导致函数变慢,Firebug还有一个分析器

编辑: 对于未来的读者来说,下面的答案推荐使用JSPerf应该是正确答案。我想删除我的答案,但由于已被 OP 选择,因此无法删除。性能基准测试不仅仅是运行多次迭代,JSPerf会为您处理其他事项。


12
仅仅计时您的代码的预定义迭代次数并不能完全保证测试结果的准确性。同时,开启 Firebug 将会禁用 Firefox 的即时编译器(JIT),这意味着测试将在解释器中运行,比本来应有的速度慢得多。使用 Firebug 的分析工具也无法给出您期望的结果。 - Mathias Bynens
1
@Mathias:好吧,公平地说,这个答案真的很老了。 - Sasha Chedygov
2
当然,不冒犯你啊伙计。我只是想评论一下,现在对这个主题进行了更多的研究,以备将来参考。 - Mathias Bynens
4
请将文本从英语翻译成中文。仅返回翻译后的文本:或使用http://jsben.ch,因为jsperf已关闭。 - EscapeNetscape

23

我一直在使用@musicfreaks回答的这个简单实现。虽然没有特色,但使用起来非常容易。这个bench(function(){return 1/2;}, 10000, [], this)将会计算1/2 10,000次。

/**
 * Figure out how long it takes for a method to execute.
 * 
 * @param {Function} method to test 
 * @param {number} iterations number of executions.
 * @param {Array} args to pass in. 
 * @param {T} context the context to call the method in.
 * @return {number} the time it took, in milliseconds to execute.
 */
var bench = function (method, iterations, args, context) {

    var time = 0;
    var timer = function (action) {
        var d = Date.now();
        if (time < 1 || action === 'start') {
            time = d;
            return 0;
        } else if (action === 'stop') {
            var t = d - time;
            time = 0;    
            return t;
        } else {
            return d - time;    
        }
    };

    var result = [];
    var i = 0;
    timer('start');
    while (i < iterations) {
        result.push(method.apply(context, args));
        i++;
    }

    var execTime = timer('stop');

    if ( typeof console === "object") {
        console.log("Mean execution time was: ", execTime / iterations);
        console.log("Sum execution time was: ", execTime);
        console.log("Result of the method call was:", result[0]);
    }

    return execTime;  
};

9

编写优秀的跨浏览器基准测试真的很难。仅仅计时您的代码一组预定义迭代次数并不完全可靠

正如@broofa已经建议的那样,请查看jsPerf。它在幕后使用的是Benchmark.js


2
如果您需要简单的操作,可以像这样做:
'use strict'
console.clear()

const powerOf = x => y => Math.pow(x, y)
const powerOfThree = powerOf(3)

function performanceCalc(fn, ...params) {
    const start = +new Date()
    const result = fn(...params)
    const end = +new Date()

    console.log(`Result: ${result}. Execution Time: ${end - start} ms`)
}

performanceCalc(powerOfThree, 2)

这里有一份代码示例


在我的情况下,简单绝对是最好的选择......编写一些测试来基准测试API的响应时间(不需要极其精确的时间)。 - kashiraja

2

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