基准测试是性能测试的一种,通过设计合理的测试方法,选用合适的测试工具和被测系统,实现对某个特定目标场景的某项性能指标进行定量的和可对比的测试。一般情况下当系统中增加了一个新模块时需要做基准测试,用来判断模块对整个系统的性能影响
简单的性能测试
很多时候为了测试函数的执行性能,我们会写出类似的代码:
const startTime = Date.now();
// function call
const endTime = Date.now();
console.log(`代码执行耗时 ${endTime - startTime}ms`);
这样的代码会有几个明显的限制
- 精度:很多函数的执行耗时小于 1ms,这样就看不出执行耗时
- 环境影响:无论是代码在浏览器还是 Node.js 执行,都难免受到机器运行状态等影响,重复测试取得的结果可能大相径庭
- 不能确定引擎是否对这段测试代码进行了优化。在真实程序中引擎是否会同样优化这段代码,如果不能这就会导致真实环境中代码运行变慢
- 数学问题:简单把测试跑 100 遍,然后取平均值并不能让测试结果精准,去掉一个最高分,去掉一个最低分也不能,重复执行的次数和对应均值的计算是个复杂的数学问题
Benchmark.js
上述问题都被 benchmark.js 解决了,benchmark.js 让 JavaScript 的基准测试符合 可测量、可重复、可对比的三大原则,看个官方的例子 ```javascript const Benchmark = require(‘benchmark’);
const suite = new Benchmark.Suite; // add tests suite.add(‘RegExp#test’, function() { /o/.test(‘Hello World!’); }) .add(‘String#indexOf’, function() { ‘Hello World!’.indexOf(‘o’) > -1; }) // add listeners .on(‘cycle’, function(event) { console.log(String(event.target)); }) .on(‘complete’, function() { console.log(‘Fastest is ‘ + this.filter(‘fastest’).map(‘name’)); }) // run async .run({ ‘async’: true });
创建示例后可以调用 `add` 方法添加测试对象,添加完成后绑定事件,然后调用 `run` 方法进行测试,使用非常简单, `cycle` 会在每个测试用例调用完成之间调用
_测试结果:_
测试用例名/每秒调用数/方差/抽样数 RegExp#test x 29,718,249 ops/sec ±3.30% (85 runs sampled) String#indexOf x 769,334,065 ops/sec ±0.73% (87 runs sampled)
Fastest is String#indexOf
<a name="qrpDB"></a>
## add
add 方法有几个参数
```javascript
// 基本使用
suite.add(fn);
// 为测试用例添加名称
suite.add('foo', fn);
// options 设置事件
suite.add('foo', fn, {
'onCycle': onCycle,
'onComplete': onComplete
});
// 也可以完全使用 options 添加
suite.add({
'name': 'foo',
'fn': fn,
'onCycle': onCycle,
'onComplete': onComplete,
'setup': `console.log('start')`, // 每个测试循环开始时调用
'teardown': `console.log('over')` // 每个测试循环结束时调用
});
有意思的测试
let 和 var 定义变量,谁会快一些?
const Benchmark = require('benchmark')
const suite = new Benchmark.Suite;
const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
suite.add('let', function () {
for (let i = 0, len = arr.length; i < len; i++) {
arr[i];
}
})
.add('var', function () {
for (var i = 0, len = arr.length; i < len; i++) {
arr[i];
}
})
.on('cycle', function (event) {
console.log(String(event.target));
})
.on('complete', function () {
console.log('Fastest is ' + this.filter('fastest').map('name'));
})
.run()
var 会快一些
let x 93,508,103 ops/sec ±5.43% (83 runs sampled)
var x 94,725,310 ops/sec ±1.21% (88 runs sampled)
Fastest is var