Benchmark.js provides a comprehensive event-driven system for monitoring benchmark and suite execution with detailed progress tracking and result handling.
Standard events emitted by benchmarks and suites during execution.
// Core event types (string constants)
'start'; // Benchmark/suite execution begins
'cycle'; // Each benchmark cycle completes
'complete'; // Benchmark/suite execution finishes
'abort'; // Benchmark/suite execution is aborted
'error'; // Error occurs during execution
'reset'; // Benchmark/suite is reset to initial stateUsage Examples:
const Benchmark = require('benchmark');
const bench = new Benchmark('test', function() { Math.random(); });
// Listen to all event types
bench.on('start', function() {
console.log('Benchmark starting...');
})
.on('cycle', function(event) {
console.log('Cycle completed');
})
.on('complete', function() {
console.log('Benchmark finished');
})
.on('abort', function() {
console.log('Benchmark aborted');
})
.on('error', function(event) {
console.error('Error:', event.target.error.message);
})
.on('reset', function() {
console.log('Benchmark reset');
});Event objects passed to event listeners.
interface BenchmarkEvent {
type: string; // Event type name
target: Benchmark|Suite; // The benchmark or suite that emitted the event
timeStamp: number; // Timestamp when event was created (milliseconds)
currentTarget?: Benchmark|Suite; // Current event target (for event bubbling)
result?: any; // Event result data (varies by event type)
aborted?: boolean; // Whether the event was aborted
cancelled?: boolean; // Whether the event was cancelled
}Usage Examples:
const bench = new Benchmark('test', function() { Math.random(); });
bench.on('cycle', function(event) {
console.log('Event type:', event.type); // "cycle"
console.log('Target name:', event.target.name); // "test"
console.log('Timestamp:', event.timeStamp); // e.g., 1609459200000
console.log('Target:', event.target.toString()); // Benchmark results
});
bench.on('error', function(event) {
console.log('Error event:', event.type); // "error"
console.log('Error object:', event.target.error); // Error instance
console.log('Was aborted:', event.aborted); // boolean
});Events specific to individual benchmark execution.
// Benchmark event lifecycle
benchmark.on('start', function(event) {
// Called when benchmark begins execution
// event.target = the benchmark instance
});
benchmark.on('cycle', function(event) {
// Called after each benchmark cycle completes
// event.target = the benchmark instance with updated stats
});
benchmark.on('complete', function(event) {
// Called when benchmark execution finishes
// event.target = the benchmark instance with final results
});
benchmark.on('abort', function(event) {
// Called when benchmark is aborted
// event.target = the benchmark instance
});
benchmark.on('error', function(event) {
// Called when benchmark encounters an error
// event.target = the benchmark instance
// event.target.error = Error object
});
benchmark.on('reset', function(event) {
// Called when benchmark is reset
// event.target = the benchmark instance (reset to initial state)
});Usage Examples:
const bench = new Benchmark('async-test', function(deferred) {
setTimeout(function() {
deferred.resolve();
}, 1);
}, { defer: true });
bench.on('start', function() {
console.log('Starting async benchmark');
this.startTime = Date.now();
})
.on('cycle', function(event) {
const bench = event.target;
console.log(`Cycle: ${bench.cycles}, Hz: ${bench.hz.toFixed(2)}`);
})
.on('complete', function() {
const totalTime = Date.now() - this.startTime;
console.log(`Completed in ${totalTime}ms`);
console.log(`Final result: ${this.toString()}`);
})
.on('error', function(event) {
console.error('Async benchmark failed:', event.target.error);
});
bench.run();Events specific to suite execution and benchmark coordination.
// Suite event lifecycle
suite.on('start', function(event) {
// Called when suite begins execution
// event.target = the suite instance
});
suite.on('cycle', function(event) {
// Called after each benchmark in the suite completes
// event.target = the individual benchmark that completed
});
suite.on('complete', function(event) {
// Called when all benchmarks in suite finish
// event.target = the suite instance
// this = the suite instance (for convenience)
});
suite.on('abort', function(event) {
// Called when suite execution is aborted
// event.target = the suite instance
});
suite.on('error', function(event) {
// Called when any benchmark in suite encounters error
// event.target = the specific benchmark with error
});
suite.on('reset', function(event) {
// Called when suite is reset
// event.target = the suite instance
});Usage Examples:
const suite = new Benchmark.Suite('String Performance');
suite.add('RegExp#test', function() {
/o/.test('Hello World!');
})
.add('String#indexOf', function() {
'Hello World!'.indexOf('o') > -1;
})
.add('String#match', function() {
'Hello World!'.match(/o/);
});
let benchmarkCount = 0;
suite.on('start', function() {
console.log('Suite started with', this.length, 'benchmarks');
})
.on('cycle', function(event) {
benchmarkCount++;
console.log(`[${benchmarkCount}/${this.length}] ${String(event.target)}`);
})
.on('complete', function() {
console.log('\nSuite completed!');
console.log('Fastest:', this.filter('fastest').map('name').join(', '));
console.log('Slowest:', this.filter('slowest').map('name').join(', '));
// Detailed results
this.forEach(function(benchmark) {
const rme = benchmark.stats.rme.toFixed(2);
const samples = benchmark.stats.sample.length;
console.log(`${benchmark.name}: ${benchmark.hz.toFixed(0)} ops/sec ±${rme}% (${samples} runs)`);
});
})
.on('error', function(event) {
console.error(`Error in "${event.target.name}":`, event.target.error.message);
});
suite.run({ async: true });Understanding the this context in event handlers.
// Event handler context varies by attachment method
// Method 1: Direct event handler - 'this' is the target
benchmark.on('complete', function() {
console.log(this.name); // 'this' = benchmark instance
});
// Method 2: Options event handler - 'this' is the target
const bench = new Benchmark('test', function() {}, {
onComplete: function() {
console.log(this.name); // 'this' = benchmark instance
}
});
// Method 3: Arrow functions - 'this' is lexical scope
benchmark.on('complete', () => {
console.log(this); // 'this' = outer scope, not benchmark
});Usage Examples:
const suite = new Benchmark.Suite('Context Demo');
suite.add('test1', function() { Math.random(); })
.add('test2', function() { Math.round(Math.random()); });
// Regular function - 'this' is suite
suite.on('complete', function() {
console.log('Suite name:', this.name); // Suite name
console.log('Benchmark count:', this.length); // Number of benchmarks
// Access individual benchmarks
this.forEach(function(benchmark) {
console.log('Benchmark:', benchmark.name, benchmark.hz);
});
});
// Arrow function - 'this' is outer scope
suite.on('cycle', (event) => {
console.log('Completed:', event.target.name); // Must use event.target
});
// Options-based handler
const bench = new Benchmark('options-demo', function() { Math.random(); }, {
onComplete: function() {
console.log('My name:', this.name); // 'this' = benchmark
console.log('My result:', this.toString());
}
});Advanced event handling patterns and techniques.
// Event delegation and bubbling
suite.on('cycle', function(event) {
// Handle events from all benchmarks in suite
const benchmark = event.target;
if (benchmark.error) {
console.log('Benchmark failed:', benchmark.name);
} else {
console.log('Benchmark succeeded:', benchmark.name);
}
});
// Conditional event handling
benchmark.on('complete', function() {
if (this.hz < 1000) {
console.warn('Performance warning: low ops/sec');
}
if (this.stats.rme > 5) {
console.warn('Precision warning: high variance');
}
});
// Event chaining and coordination
suite.on('complete', function() {
// Chain to another suite
const nextSuite = new Benchmark.Suite('Follow-up Tests');
// ... configure next suite
nextSuite.run();
});Usage Examples:
// Performance monitoring suite
const monitoringSuite = new Benchmark.Suite('Performance Monitor');
monitoringSuite
.add('fast-operation', function() {
const arr = [1, 2, 3];
arr.join(',');
})
.add('slow-operation', function() {
const arr = new Array(1000).fill(0);
arr.map(x => x * 2).filter(x => x > 0).reduce((a, b) => a + b, 0);
});
// Advanced monitoring
monitoringSuite.on('cycle', function(event) {
const bench = event.target;
const stats = bench.stats;
// Performance thresholds
if (bench.hz < 10000) {
console.warn(`⚠️ Low performance: ${bench.name} (${bench.hz.toFixed(0)} ops/sec)`);
}
// Precision thresholds
if (stats.rme > 3) {
console.warn(`⚠️ High variance: ${bench.name} (±${stats.rme.toFixed(2)}%)`);
}
// Memory usage (if available)
if (typeof process !== 'undefined' && process.memoryUsage) {
const memory = process.memoryUsage();
console.log(`📊 Memory: ${(memory.heapUsed / 1024 / 1024).toFixed(2)}MB`);
}
});
monitoringSuite.on('complete', function() {
// Generate performance report
const results = this.map(bench => ({
name: bench.name,
opsPerSec: bench.hz,
rme: bench.stats.rme,
samples: bench.stats.sample.length
}));
console.log('\n📈 Performance Report:');
results.forEach(result => {
console.log(`${result.name}: ${result.opsPerSec.toFixed(0)} ops/sec (±${result.rme.toFixed(2)}%)`);
});
});
monitoringSuite.run({ async: true });Specialized error handling patterns.
// Error event properties
errorEvent.target.error; // Error object
errorEvent.target.name; // Benchmark name that failed
errorEvent.type; // "error"
errorEvent.timeStamp; // When error occurred
// Global error handling
Benchmark.prototype.on = function(type, listener) {
if (type === 'error') {
// Wrap listener with additional error handling
const wrappedListener = function(event) {
console.error('Benchmark error in:', event.target.name);
console.error('Error details:', event.target.error);
listener.call(this, event);
};
return originalOn.call(this, type, wrappedListener);
}
return originalOn.call(this, type, listener);
};Usage Examples:
// Comprehensive error handling
const suite = new Benchmark.Suite('Error Handling Demo');
suite.add('good-test', function() {
Math.random();
})
.add('bad-test', function() {
throw new Error('Intentional test error');
})
.add('async-error', function(deferred) {
setTimeout(function() {
deferred.reject(new Error('Async error'));
}, 1);
}, { defer: true });
// Suite-level error handling
suite.on('error', function(event) {
const benchmark = event.target;
console.error(`❌ Error in "${benchmark.name}":`, benchmark.error.message);
// Continue with other benchmarks
console.log('Continuing with remaining benchmarks...');
});
// Individual benchmark error handling
suite.forEach(function(benchmark) {
benchmark.on('error', function(event) {
console.log(`Benchmark "${this.name}" failed, but suite continues`);
});
});
suite.on('complete', function() {
const successful = this.filter(function(bench) { return !bench.error; });
const failed = this.filter(function(bench) { return bench.error; });
console.log(`\n✅ Successful: ${successful.length}`);
console.log(`❌ Failed: ${failed.length}`);
if (successful.length > 0) {
console.log('Fastest of successful:', successful.filter('fastest').map('name'));
}
});
suite.run();// Event order for successful benchmark
'start' → 'cycle' → 'cycle' → ... → 'complete'
// Event order for aborted benchmark
'start' → 'cycle' → ... → 'abort'
// Event order for failed benchmark
'start' → 'cycle' → ... → 'error'
// Event order for reset benchmark
'reset' (can occur at any time)interface BenchmarkEvent {
type: string; // Event type name
target: Benchmark | Suite; // Source of event
currentTarget?: Benchmark | Suite; // Current event target
timeStamp: number; // Event creation time (ms)
result?: any; // Event-specific result data
aborted?: boolean; // Event abortion state
cancelled?: boolean; // Event cancellation state
}