var saltVal = crypto.getRandomValues(new Uint8Array(16));
function arrayBufferToHexString(bytes) {
bytes = new Uint8Array(bytes);
var hex = new Array(bytes.length);
for (let i = 0; i < bytes.length; i++) {
hex[i] = ("0" + bytes[i].toString(16)).slice(-2);
}
return hex.join("");
}
function bytesToHexString(bytes) {
bytes = new Uint8Array(bytes);
var hexBytes = [];
for (var i = 0; i < bytes.length; i++) {
var byteString = bytes[i].toString(16);
if (byteString.length < 2) byteString = "0" + byteString;
hexBytes.push(byteString);
}
return hexBytes.join("");
}
function buf2hex(buffer) { // buffer is an ArrayBuffer
return [new Uint8Array(buffer)]
.map(x => x.toString(16).padStart(2, '0'))
.join('');
}
function hex(arrayBuffer)
{
const asciiCodes = new Uint8Array(
Array.prototype.map.call(
"0123456789abcdef",
char => char.charCodeAt()
)
);
const buff = new Uint8Array(arrayBuffer);
const charCodes = new Uint8Array(buff.length * 2);
for (let i = 0; i < buff.length; ++i)
{
charCodes[i * 2] = asciiCodes[buff[i] >>> 4];
charCodes[i * 2 + 1] = asciiCodes[buff[i] & 0xf];
}
return String.fromCharCode(charCodes);
}
function hex2(arrayBuffer)
{
return Array.prototype.map.call(
new Uint8Array(arrayBuffer),
n => n.toString(16).padStart(2, "0")
).join("");
}
function arrayBufferToBase64(buffer) {
const byteArray = new Uint8Array(buffer);
const binaryString = byteArray.reduce((acc, byte) => acc + String.fromCharCode(byte), "");
return btoa(binaryString);
}
function arrayBufferToBase64loop( buffer ) {
var binary = '';
var bytes = new Uint8Array( buffer );
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode( bytes[ i ] );
}
return window.btoa( binary );
}
function bytesToHexString2(bytes) {
bytes = new Uint8Array(bytes);
var hexBytes = '';
for (var i = 0; i < bytes.length; i++) {
var byteString = bytes[i].toString(16);
if (byteString.length < 2) byteString = "0" + byteString;
hexBytes += byteString;
}
return hexBytes;
}
function bytesToHexString3(bytes) {
bytes = new Uint8Array(bytes);
var hexBytes = '';
for (var i = 0; i < bytes.length; i++) {
var byteString = bytes[i].toString(16);
if (byteString.length < 2) hexBytes += "0";
hexBytes += byteString;
}
return hexBytes;
}
function bytesToHexString4(bytes) {
bytes = new Uint8Array(bytes);
var hexBytes = '';
for (var i = 0; i < bytes.length; i++) {
hexBytes += bytes[i].toString(16).padStart(2, '0');
}
return hexBytes;
}
arrayBufferToHexString(saltVal);
bytesToHexString(saltVal)
buf2hex(saltVal)
hex(saltVal)
hex2(saltVal)
arrayBufferToBase64(saltVal)
arrayBufferToBase64loop(saltVal)
bytesToHexString2(saltVal)
bytesToHexString3(saltVal)
bytesToHexString4(saltVal)
--enable-precise-memory-info
flag.
Test case name | Result |
---|---|
directly set | |
push values | |
buf2hex() | |
precomputed ASCII with shift | |
array prototype map | |
base64 | |
base64 loop | |
string + | |
string + 2 | |
string + pad |
Test name | Executions per second |
---|---|
directly set | 2449344.0 Ops/sec |
push values | 3418329.5 Ops/sec |
buf2hex() | 1701248.1 Ops/sec |
precomputed ASCII with shift | 864891.2 Ops/sec |
array prototype map | 1193146.8 Ops/sec |
base64 | 3353756.8 Ops/sec |
base64 loop | 4347946.5 Ops/sec |
string + | 5316500.0 Ops/sec |
string + 2 | 5316376.5 Ops/sec |
string + pad | 4910442.0 Ops/sec |
The benchmark defined in the JSON represents a comparison of various methods for converting an ArrayBuffer to hexadecimal string and base64 encoding in JavaScript. The objective is to evaluate the performance efficiency of these different methods by measuring the number of executions per second for each approach. Here’s a breakdown of the methods being compared, their pros and cons, considerations, and alternatives.
Directly Set (arrayBufferToHexString
):
Push Values (bytesToHexString
):
buf2hex
:
Uint8Array
and maps each byte to a hexadecimal string.Precomputed ASCII with Shift (hex
):
Array Prototype Map (hex2
):
Array.prototype.map
to iterate through the bytes, converting them to hex.bytesToHexString2
, bytesToHexString3
, bytesToHexString4
:
Base64 (arrayBufferToBase64
):
btoa
.Base64 Loop (arrayBufferToBase64loop
):
The latest results show significant variations in executions per second among the methods tested:
bytesToHexString2
(string concatenation) exhibits the best performance (5,316,500 executions/second).bytesToHexString4
and arrayBufferToBase64loop
follow closely behind, indicating that string manipulation and loop-based methods may still perform reasonably well.buf2hex()
and hex()
show poorer performance results, potentially due to overhead from more complex operations or abstractions.While the benchmark tests several methods in pure JavaScript, alternative approaches could include:
WebAssembly: For performance-sensitive applications, implementing these conversions in WebAssembly could provide a notable boost, especially for high-frequency operations.
Dedicated Libraries: Libraries such as Buffer
in Node.js or crypto
based libraries can handle conversions more efficiently and abstract away these operations, although they may come with their own overheads and dependencies.
Typed Arrays: Other advanced techniques using JavaScript’s typed arrays can be explored for greater efficiency, especially when dealing with raw binary data.
The benchmark allows developers to directly compare multiple approaches for ArrayBuffer conversions, emphasizing the trade-offs between clarity, performance, and complexity. Selecting the right method will depend on the specific use case, data sizes, and performance requirements.