function test(bin, bytes){
var r, i;
hex = '', chars = '\n: -';
//generate an array of random octets and
//a corresponding hex string
for(i = 0; i < bytes; i++){
r = Math.random() * 0x100 | 0,
bin[i] = (r & 0xff);
hex += (r >> 4).toString(16) + (r & 0xf).toString(16);
}
//insert non-hex characters at random positions in hex string
for(i = 0; i < 10; i++){
r = Math.random() * hex.length | 0;
hex = hex.slice(0, r) + chars.charAt(r & 3) + hex.slice(r);
}
return hex;
}
var expected = [],
testCase = test(expected, 10000);
function parseHex1(hex){// original
hex = hex.replace(/[^0-9a-fA-F]/g, '');
var i,
len = hex.length,
bin = [];
for(i = 0; i < len - 1; i += 2){
bin.push(+('0x' + hex.substring(i, i + 2)));
}
return bin;
}
function parseHex2(string) {// replace match map ES5
return string.replace(/[^0-9a-fA-F]/g, '').match(/[0-9a-fA-F]{2}/g).map(function(hex) {
return parseInt(hex, 16);
});
}
function parseHex3(hex){//match without replace
hex = hex.match(/[\da-f]/gi);
for(var i = 0; i < hex.length - 1; i += 2){
hex[i >> 1] = +('0x' + hex[i] + hex[i + 1]);
}
hex.length = i >> 1;
return hex;
}
function parseHex4(hex){// iteration with replace
var bin = [];
hex.replace(/([\da-f])[^\da-f]*([\da-f])/gi,
function(m, digit1, digit2){
bin.push(+('0x' + digit1 + digit2));
}
);
return bin;
}
function parseHex5(hex){// looping with exec
var bin = [],
regex = /([\da-f])[^\da-f]*([\da-f])/gi,
result;
while(result = regex.exec(hex)){
bin.push(+('0x' + result[1] + result[2]));
}
return bin;
}
function parseHex6(hex){// non regex
var bin = [], i, c, isEmpty = 1, buffer;
for(i = 0; i < hex.length; i++){
c = hex.charCodeAt(i);
if(c > 47 && c < 58 || c > 64 && c < 71 || c > 96 && c < 103){
buffer = buffer << 4 ^ (c > 64 ? c + 9 : c) & 15;
if(isEmpty ^= 1){
bin.push(buffer & 0xff);
}
}
}
return bin;
}
parseHex1(testCase);
parseHex2(testCase);
parseHex3(testCase);
parseHex4(testCase);
parseHex5(testCase);
parseHex6(testCase);
--enable-precise-memory-info
flag.
Test case name | Result |
---|---|
original | |
ES5 replace match map | |
match without replace | |
iteration with replace | |
looping with exec | |
non regex |
Test name | Executions per second |
---|---|
original | 2049.3 Ops/sec |
ES5 replace match map | 1033.9 Ops/sec |
match without replace | 1881.7 Ops/sec |
iteration with replace | 983.1 Ops/sec |
looping with exec | 1110.2 Ops/sec |
non regex | 6823.9 Ops/sec |
Let's dive into the world of JavaScript microbenchmarks!
Benchmark Definition
The benchmark defines a function test(bin, bytes)
that generates an array of random octets and its corresponding hex string. The purpose is to parse this hex string.
Test Cases
There are six test cases:
parseHex1
.replace()
method.exec()
method to parse the hex string.Browser Benchmarks
The latest benchmark results show the execution rates for each test case across multiple devices and browsers:
Analysis
The results suggest that:
The other implementations fall in between, with varying degrees of performance. It's essential to note that these results are specific to this particular benchmark and may not generalize to all use cases.
It's also worth mentioning that the Looping with exec implementation is slower than expected, which might be due to the overhead of using exec()
or some other internal engine-specific optimizations.
In summary, this benchmark provides valuable insights into the performance characteristics of different JavaScript implementations for parsing hex strings.