Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Performance - target es2018 #1022

Merged
merged 2 commits into from
Mar 18, 2022
Merged

Performance - target es2018 #1022

merged 2 commits into from
Mar 18, 2022

Conversation

tmcw
Copy link
Contributor

@tmcw tmcw commented Mar 17, 2022

So the current setup is that zod has a compile target of es5, which applies to both its ES Module and CJS distributions. Zod's internals use quite a lot of modern features. TypeScript is polyfilling all of those features in the distributed code. TypeScript's polyfills are very good and probably as fast as they can be, but they're not as fast as the native code. For example, every array or object spread and every generator gets compiled to something with a bit more indirection.

That indirection looks like it's costing a real slowdown for some Zod functions.

So, bumping the target to ES2018 would cost IE11 support if it was done uniformly. Assuming that IE11 support is still critical (that's for the maintainers to decide, not me), a possibility might be targeting es2018 in the module entrypoint and keeping es5 in the main.

Okay, so before:

~/p/zod on es2018 [$!]
130 % y benchmark
yarn run v1.22.4
$ ts-node src/benchmarks/index.ts
z.string: empty string x 2,451,532 ops/sec ±0.87% (94 runs sampled)
z.string: short string x 2,482,775 ops/sec ±0.45% (95 runs sampled)
z.string: long string x 2,404,051 ops/sec ±1.38% (91 runs sampled)
z.string: invalid: null x 89,502 ops/sec ±0.97% (89 runs sampled)
z.string: manual parser: long x 874,138,478 ops/sec ±1.56% (87 runs sampled)
z.object: empty: valid x 1,646,418 ops/sec ±5.48% (91 runs sampled)
z.object: empty: valid: extra keys x 1,559,284 ops/sec ±0.80% (91 runs sampled)
z.object: empty: invalid: null x 90,326 ops/sec ±0.92% (95 runs sampled)
z.object: short: valid x 790,794 ops/sec ±0.94% (94 runs sampled)
z.object: short: valid: extra keys x 763,664 ops/sec ±6.08% (90 runs sampled)
z.object: short: invalid: null x 90,299 ops/sec ±0.63% (93 runs sampled)
z.object: long: valid x 412,393 ops/sec ±0.45% (97 runs sampled)
z.object: long: valid: extra keys x 391,355 ops/sec ±5.61% (92 runs sampled)
z.object: long: invalid: null x 88,410 ops/sec ±0.95% (93 runs sampled)
z.union: double: valid: a x 256,918 ops/sec ±0.60% (96 runs sampled)
z.union: double: valid: b x 256,784 ops/sec ±0.39% (96 runs sampled)
z.union: double: invalid: null x 28,961 ops/sec ±6.36% (84 runs sampled)
z.union: double: invalid: wrong shape x 24,945 ops/sec ±6.41% (87 runs sampled)
z.union: many: valid: a x 126,783 ops/sec ±0.55% (93 runs sampled)
z.union: many: valid: c x 124,881 ops/sec ±1.09% (92 runs sampled)
z.union: many: invalid: null x 16,535 ops/sec ±5.17% (86 runs sampled)
z.union: many: invalid: wrong shape x 14,627 ops/sec ±6.94% (86 runs sampled)
z.discriminatedUnion: double: valid: a x 667,578 ops/sec ±0.44% (96 runs sampled)
z.discriminatedUnion: double: valid: b x 663,500 ops/sec ±0.54% (96 runs sampled)
z.discriminatedUnion: double: invalid: null x 88,595 ops/sec ±0.85% (95 runs sampled)
z.discriminatedUnion: double: invalid: wrong shape x 84,477 ops/sec ±0.62% (94 runs sampled)
z.discriminatedUnion: many: valid: a x 660,361 ops/sec ±0.39% (92 runs sampled)
z.discriminatedUnion: many: valid: c x 665,620 ops/sec ±0.84% (93 runs sampled)
z.discriminatedUnion: many: invalid: null x 91,685 ops/sec ±0.70% (92 runs sampled)
z.discriminatedUnion: many: invalid: wrong shape x 83,539 ops/sec ±0.67% (90 runs sampled)
✨  Done in 164.98s.

After:

% y benchmark
yarn run v1.22.4
$ ts-node src/benchmarks/index.ts
z.string: empty string x 7,456,311 ops/sec ±0.50% (94 runs sampled)
z.string: short string x 7,294,686 ops/sec ±0.63% (94 runs sampled)
z.string: long string x 7,267,118 ops/sec ±0.74% (92 runs sampled)
z.string: invalid: null x 68,995 ops/sec ±3.45% (90 runs sampled)
z.string: manual parser: long x 873,026,560 ops/sec ±1.81% (86 runs sampled)
z.object: empty: valid x 3,947,137 ops/sec ±0.54% (95 runs sampled)
z.object: empty: valid: extra keys x 3,381,157 ops/sec ±0.55% (93 runs sampled)
z.object: empty: invalid: null x 68,712 ops/sec ±0.78% (95 runs sampled)
z.object: short: valid x 1,699,620 ops/sec ±30.55% (93 runs sampled)
z.object: short: valid: extra keys x 1,940,140 ops/sec ±0.82% (94 runs sampled)
z.object: short: invalid: null x 69,124 ops/sec ±0.47% (94 runs sampled)
z.object: long: valid x 899,629 ops/sec ±0.53% (94 runs sampled)
z.object: long: valid: extra keys x 839,770 ops/sec ±0.77% (95 runs sampled)
z.object: long: invalid: null x 67,109 ops/sec ±3.32% (92 runs sampled)
z.union: double: valid: a x 177,326 ops/sec ±6.18% (90 runs sampled)
z.union: double: valid: b x 175,326 ops/sec ±5.59% (86 runs sampled)
z.union: double: invalid: null x 23,836 ops/sec ±3.96% (89 runs sampled)
z.union: double: invalid: wrong shape x 23,462 ops/sec ±0.86% (92 runs sampled)
z.union: many: valid: a x 72,148 ops/sec ±6.87% (86 runs sampled)
z.union: many: valid: c x 75,365 ops/sec ±4.36% (92 runs sampled)
z.union: many: invalid: null x 14,744 ops/sec ±3.83% (89 runs sampled)
z.union: many: invalid: wrong shape x 14,380 ops/sec ±0.62% (93 runs sampled)
z.discriminatedUnion: double: valid: a x 730,682 ops/sec ±0.42% (96 runs sampled)
z.discriminatedUnion: double: valid: b x 723,743 ops/sec ±0.39% (95 runs sampled)
z.discriminatedUnion: double: invalid: null x 61,431 ops/sec ±3.81% (90 runs sampled)
z.discriminatedUnion: double: invalid: wrong shape x 69,464 ops/sec ±0.82% (93 runs sampled)
z.discriminatedUnion: many: valid: a x 730,148 ops/sec ±0.74% (96 runs sampled)
z.discriminatedUnion: many: valid: c x 732,561 ops/sec ±0.55% (94 runs sampled)
z.discriminatedUnion: many: invalid: null x 65,482 ops/sec ±0.64% (94 runs sampled)
z.discriminatedUnion: many: invalid: wrong shape x 69,293 ops/sec ±0.47% (93 runs sampled)
✨  Done in 165.41s.

@tmcw tmcw mentioned this pull request Mar 17, 2022
@colinhacks
Copy link
Owner

I ran a diff and basically the only difference is that es2018 no longer transpiles the spread operator to Object.assigns under the hood. Guess the spread can be faster in some cases...kinda surprising.

IE11 support isn't a priority and a 2x speed improvement is hard to turn down. Merging.

@colinhacks colinhacks merged commit 4acff9c into colinhacks:master Mar 18, 2022
@syabro
Copy link

syabro commented Sep 27, 2022

So no ie11 anymore?

@FlorianWendelborn
Copy link
Contributor

@syabro you can either use an older version, or transpile it down to es5. Not a big deal

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants