base64-js
base64-js copied to clipboard
Performance improvements and fixed a bug in fromByteArray() when extra bytes are negative
Performance improvements:
- Pre-allocating arrays in
encodeChunk()
andfromByteArray()
- Removing unnecessary operations, e.g. increments of a variable that is never used again
- Using bitwise operators (e.g.
& 3
instead of% 4
and|
instead of+
) where possible - Removing an unnecessary argument being passed to
_byteLength()
- Removing unnecessary branching
I see a speed increase of about 10% in the benchmark for fromByteArray()
.
Also fixed a bug with fromByteArray()
when it is passed negative "extra bytes," i.e. bytes at or after the last index that is a multiple of 3. encodeChunk()
masks each byte with 0xFF
, but this was missing in the logic for when extraBytes
is 1 or 2. It's not clear to me why it's necessary to support passing in negative bytes (especially as this is impossible with a Uint8Array
), but there are test cases that do so, so I wanted to make the code consistent.
More efficient is to use string concat then parts
array, e.g. see https://jsperf.com/javascript-concat-vs-join/2
I found it was possible to slightly improve performance by using string concatenation of the encoded chunks, but using string concatenation in encodeChunk()
led to significant performance decreases:
join() for all
base64.fromByteArray() (encode) x 58.66 ops/sec ±1.24% (61 runs sampled)
+= between chunks, join() within chunk
base64.fromByteArray() (encode) x 62.62 ops/sec ±1.14% (65 runs sampled)
+= for all
base64.fromByteArray() (encode) x 20.20 ops/sec ±1.43% (38 runs sampled)
@calebsander Can you share output from running the performance suite before and after your changes? Thanks.
Sure. Here is the output from running node bench/bench.js
on the upstream master (08a344d):
base64.toByteArray() (decode) x 320 ops/sec ±0.77% (88 runs sampled)
base64.fromByteArray() (encode) x 60.11 ops/sec ±0.90% (62 runs sampled)
base64.byteLength() (encode) x 42,536 ops/sec ±0.29% (94 runs sampled)
and with my changes (804d47e):
base64.toByteArray() (decode) x 342 ops/sec ±0.77% (90 runs sampled)
base64.fromByteArray() (encode) x 64.79 ops/sec ±0.57% (67 runs sampled)
base64.byteLength() (encode) x 42,628 ops/sec ±0.27% (94 runs sampled)