Closed JonasWijne closed 1 year ago
👍
This is actually slower in all cases except Nested Arrays
because the Array.isArray check is moved up.
This appears tricky – sorry – but its because the latter (mostly repeat) candidate gets to benefit from JIT optimizations.
I added some more to illustrate:
clsx (prev)
= clsx@1.1.0clsx
= current masterclsx (#73)
= this PR ⌁ ~/repos/oss/clsx master± node -v
v18.12.1
⌁ ~/repos/oss/clsx master± node bench
# Strings
clsx (prev) x 12,347,638 ops/sec ±0.23% (93 runs sampled)
clsx (#73) x 13,488,185 ops/sec ±0.08% (101 runs sampled)
clsx x 14,283,213 ops/sec ±0.11% (94 runs sampled)
# Objects
clsx (prev) x 8,286,705 ops/sec ±0.62% (99 runs sampled)
clsx (#73) x 10,108,131 ops/sec ±0.50% (94 runs sampled)
clsx x 10,426,194 ops/sec ±0.43% (94 runs sampled)
# Arrays
clsx (prev) x 9,758,624 ops/sec ±0.26% (101 runs sampled)
clsx (#73) x 10,445,507 ops/sec ±0.12% (98 runs sampled)
clsx x 10,494,471 ops/sec ±0.12% (100 runs sampled)
# Nested Arrays
clsx (prev) x 7,944,617 ops/sec ±0.39% (100 runs sampled)
clsx (#73) x 8,832,563 ops/sec ±0.12% (101 runs sampled)
clsx x 8,112,300 ops/sec ±0.72% (95 runs sampled)
# Nested Arrays w/ Objects
clsx (prev) x 7,211,581 ops/sec ±1.47% (96 runs sampled)
clsx (#73) x 8,298,702 ops/sec ±1.24% (95 runs sampled)
clsx x 8,320,432 ops/sec ±0.49% (94 runs sampled)
# Mixed
clsx (prev) x 8,105,500 ops/sec ±0.18% (99 runs sampled)
clsx (#73) x 8,611,596 ops/sec ±0.58% (96 runs sampled)
clsx x 9,158,882 ops/sec ±0.52% (99 runs sampled)
# Mixed (Bad Data)
clsx (prev) x 3,264,060 ops/sec ±0.46% (99 runs sampled)
clsx (#73) x 3,553,928 ops/sec ±0.41% (99 runs sampled)
clsx x 3,703,517 ops/sec ±0.49% (99 runs sampled)
As mentioned, clsx (#73)
is only faster in Nested Arrays
.
The ES6+ bits used here are mostly just sugar for the developer, but bring runtime costs. We can see this in action by swapping the benchmark order:
# Strings
clsx (prev) x 12,365,782 ops/sec ±0.13% (98 runs sampled)
clsx x 14,292,334 ops/sec ±0.06% (101 runs sampled)
clsx (#73) x 13,477,591 ops/sec ±0.10% (99 runs sampled)
# Objects
clsx (prev) x 8,560,716 ops/sec ±0.11% (99 runs sampled)
clsx x 10,526,618 ops/sec ±0.16% (95 runs sampled)
clsx (#73) x 10,306,068 ops/sec ±0.13% (98 runs sampled)
# Arrays
clsx (prev) x 9,617,684 ops/sec ±0.16% (98 runs sampled)
clsx x 10,529,453 ops/sec ±0.12% (102 runs sampled)
clsx (#73) x 9,962,834 ops/sec ±0.49% (98 runs sampled)
# Nested Arrays
clsx (prev) x 7,691,389 ops/sec ±0.16% (99 runs sampled)
clsx x 8,494,205 ops/sec ±0.13% (100 runs sampled)
clsx (#73) x 8,650,357 ops/sec ±0.10% (99 runs sampled)
# Nested Arrays w/ Objects
clsx (prev) x 7,597,622 ops/sec ±0.36% (96 runs sampled)
clsx x 8,444,634 ops/sec ±0.19% (98 runs sampled)
clsx (#73) x 8,308,614 ops/sec ±0.16% (102 runs sampled)
# Mixed
clsx (prev) x 8,034,305 ops/sec ±0.24% (99 runs sampled)
clsx x 9,458,763 ops/sec ±0.12% (99 runs sampled)
clsx (#73) x 8,789,075 ops/sec ±0.79% (94 runs sampled)
# Mixed (Bad Data)
clsx (prev) x 3,230,945 ops/sec ±0.71% (98 runs sampled)
clsx x 3,759,799 ops/sec ±0.20% (100 runs sampled)
clsx (#73) x 3,640,722 ops/sec ±0.13% (95 runs sampled)
Even though it's running last (and should have everything JIT-wise going in its favor), it's still slightly slower than clsx
directly. That's only not true with the Nested Arrays
test since that check is still sooner.
If you want to open another PR that just moves the Array.isArray
check to its own else if
branch, I think that's the best nugget from here.
Thanks!
👍
This PR optimizes the clsx implementation, resulting in more legible and faster code. the benchmarks show improved performance compared to the previous version.
Changes:
Updated toVal function to handle different input types more efficiently. Refactored the clsx function to use a more concise approach. Benchmark results:
The updated implementation outperforms the previous version in all test cases.
The resulting build files are also smaller